仅对无符号整数进行编码时的base64字符串长度计算



我正试图计算出我可以用5个64进制字符、6个字符等编码的无符号整数的估计值

通过编程方法,我发现我可以对进行编码

2^28 - 1 = 268,435,455

具有6个字符和

2^35 - 1 = 34,359,738,368

有7个字符。

(-1,因为我从uint 1开始(

不过,我很难概括这一点,因为我假设它从2^8 = 256开始,但我不明白我是如何在2835结束的。

这是我在Go 中的实现

func Shorten(num uint64) string {
buf := make([]byte, binary.MaxVarintLen64)
n := binary.PutUvarint(buf, num)
b := buf[:n]
encoded := base64.URLEncoding.EncodeToString(b)
return strings.Replace(encoded, "=", "", -1)
}

还有

0 -> AA
128 -> gAE
16384 -> gIAB
2097152 -> gICAAQ
268435456 -> gICAgAE

所以它看起来是以7个增量上升的:2^7,2^14,2^21,等等,但为什么是7?

一个字节是8位,因此可能有256个值。基64使用64个不同的字符进行编码,因此使用6个比特。那么,在6位中可以容纳多少个8位对象呢?0,如果是四舍五入,则为3/4。然而,当你开始谈论对整数进行编码时,你的数字似乎没有意义。你说的是用ascii写的整数吗?有了6个base64字符,你就有36个比特可以玩,所以如果你谈论的是二进制32位无符号整数,你可以一次编码一个,但你可以对其中任何一个进行编码,以获得2**32种不同的可能性,然后是4个浪费的比特。使用ascii,您将有4个字符,因此它将有10000种不同的可能性(0到9999(。

你得到了意想不到的结果,因为你使用的go变量并没有被编码为正则二进制整数。为您提供一些ipython输出:

In [22]: base64.b64encode((128).to_bytes(1,'little'))                                                                                          
Out[22]: b'gA=='

因为128可以编码在单个8位字节中,所以只有2个字符带有一些填充。看看这个:

In [3]: base64.b64decode('gAE=')                                                                                                               
Out[3]: b'x80x01'
In [4]: int.from_bytes(_,'little')                                                                                                             
Out[4]: 384

因此,正如你所看到的,PutUVarint不仅仅是编码一个可变长度的整数,它还编码了一个可变整数,即它的编码方式可以在不事先知道它的大小的情况下进行解码。如果你查看variant-go模块的源代码,它描述了这个过程。Go使用每个字节的7位来保存实际的整数二进制数据,最高有效位是一个标志,表示是否还有更多的数据。128只是一个字节集的最高有效位。因此,基本上,根据你完成这项任务的方式,你要编码两次。如果你有一个给定的整数将其编码为varint,你需要整数使用的字节数*8/7来存储值,然后你对结果进行base64编码,所以你需要这个值*8/6来存储它。根据您对base64所做的操作,您可能可以确定您正在玩的字节数,而无需使用go变量,然后计算将只是8/6转换(即4/3,我只是将其保留为位,以更紧密地匹配变量过程。(

最新更新