假设您拥有无限线性二进制存储,一个很好的模式可以表示从0到无穷大的整数?


10

我想要一个表示以0开头的整数的模式,没有任何限制(假设访问无限线性存储)。

这是一个可以表示0到255之间的数字的模式:

使用存储器的第一个字节(地址0)存储整数。

现在,假设我要表示大于255的数字。当然,我可以使用多于1个字节来表示整数,但是只要它是一个固定数字,最终就会有一个太大的整数,无法用原始架构。

这是应该能够完成任务的另一个模式,但是可能效率不高。

只需使用某种唯一的“数字结尾”字节,然后使用所有前面的字节来表示数字。显然,此“数字结尾”字节不能在数字表示中的任何位置使用,但这可以通过使用base-255(而不是base-256)编号系统来实现。

但是,这很慢并且可能效率很低。我希望有一个更好的产品,它在低值的情况下表现更好并且可以很好地缩放。

本质上,它是一个UUID系统。我想看看是否有可能创建一个性能快速的UUID系统,该系统理论上可以扩展使用数年,数千年,数百万年,而无需重新设计。


1
您是否想要可以无限扩展(例如在开业之初)或数百万年(例如在您开业之初)的东西?这两个要求(显然)完全不同。64位计算机上的二进制补码扩展数百万年。
user16764 2012年

1
@ user16764,您的意思是单个64位整数变量吗?这当然是行不通的:如果600万人每秒消耗100万个UUID,那么将持续不到一个月。
Dmitri Shuralyov 2012年

1
在128位计算机上要花多长时间?
user16764 2012年

2
RFC 2550中的思想(适用于任意大的正整数)提供了按字典顺序排列的ASCII表示,可能对此适用。最终,它分解为一元代码段,该代码段编码以26为基数的段的长度,该一元代码段编码以10为基数的段的长度-后两个基数更多地与ASCII表示有关,而不是该方案的基础。
Random832

1
假设您顺序生成128位数字:如果我们通过给每个人一台petaflop计算机来限制所有计算机的计算能力,那么这些数字用完将需要900万年。另一方面,如果每个人都会随机生成6亿个128位数字,那么他们有50%的机会会生成1个重复数。这样对你足够好吗?(en.wikipedia.org/wiki/Universally_unique_identifier)如果不是,则使用256位将这两个数字乘以2 ^ 128 = 3.4 * 10 ^ 38,这比以秒为单位的宇宙年龄的平方还要大。
亚历克斯(Alex)10 Brink

Answers:


13

我使用的一种方法:计算前1位的数量n。然后,数字的大小为2 ^ n个字节(包括前1个位)。将第一个0位之后的位作为整数,并使用2 ^(n-1)个字节,使用此编码将可以由数字表示的最大值(加1)相加。

从而,

                  0 = 0b00000000
                   ...
                127 = 0b01111111
                128 = 0b1000000000000000
                   ...
              16511 = 0b1011111111111111
              16512 = 0b11000000000000000000000000000000
                   ...
          536887423 = 0b11011111111111111111111111111111
          536887424 = 0b1110000000000000000000000000000000000000000000000000000000000000
                   ...
1152921505143734399 = 0b1110111111111111111111111111111111111111111111111111111111111111
1152921505143734400 = 0b111100000000000000000000000000000000000000000000 ...

该方案允许以正好一种方式表示任何非负值。

(等效地,使用前导0位的数量。)


1
对于我来说,很难弄清楚哪个答案标记为已接受,因为我认为其中许多内容非常有用且有益。但是我认为这个问题最适合我提出的问题(可能不是我所想的基础问题,这很难表达)。
Dmitri Shuralyov

2
我写了一篇更深入的文章,其中包含示例实现和设计注意事项。
撤退

10

围绕您要尝试的工作有很多理论。看一下有关通用代码的 Wiki页面-相当详尽的整数编码方法列表(其中一些实际上已在实践中使用)。

在数据压缩中,整数通用代码是将正整数映射到二进制代码字的前缀代码。

或者,您可以仅使用前8个字节以某些单位(最可能是字节)存储数字的长度,然后放入数据字节。这将很容易实现,但对于少量用户而言效率很低。并且您将能够对整数进行足够长的编码,以填充人类可用的所有数据驱动器:)


谢谢你,这很有趣。我想将其标记为已接受的答案,但排名第二。从理论上讲,这是一个很好的答案,IMO。
Dmitri Shuralyov 2012年

4

怎么样让前导1的数量加上前0成为位数的数字大小(numSize)的大小(sizeSize)。numSize是一个二进制数字,以字节为单位给出数字表示的大小,包括大小位。其余位是二进制数(数字)。对于正整数方案,以下是一些示例示例数字:

Number              sizeSize  numSize    num
63:                 0 (1)     1 (1)      111111
1048575:            10 (2)    11 (3)     1111 11111111 11111111
1125899906842623:   110 (3)   111 (7)    11 11111111 11111111 11111111 11111111 11111111 11111111
5.19.. e+33:        1110 (4)  1111 (15)  11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

4

怎么样:一个字节的长度,然后n个字节的数字(最低有效字节在前)。只要以前的长度为255,则重复长度+数字。

这允许任意数量的数字,但是仍然易于处理并且不会浪费太多内存。


fNek:没有上限。例如,如果您需要513字节的数字,则字节序列为[255,b0,...,b255,255,b256,...,b511,2,b512,b513]
user281377 2014年

抱歉。应该学会更仔细地阅读。
fNek 2014年

3

为什么不只使用每个字节中的7位,然后使用第8位来指示是否要跟随另一个字节?因此1-127将在一个字节中,128将由0x80 0x01表示,依此类推。


1
此方案每8位仅编码128个值,这实际上比发问者提出的第二个编码方案(每8位255个值被编码)的空间效率低。这两种方案都存在这样一个事实,即您需要读取整数以找出需要存储多少存储空间。
Mark Booth

3
因此,您需要扫描两次以复制该数字,那又如何呢?如果我可以等待一个无限大的数字,那么我可以等待两次。
罗素·波罗戈夫

尽管我没有非常仔细地指定它,但我正在寻找一种性能尽可能高的解决方案(而不是简单地满足要求的解决方案;我已经在我的问题中描述了一个潜在的低效答案)。
Dmitri Shuralyov 2012年

3

UUID系统基于有限(但很大)宇宙中的有限(但很大)计算能力。UUID的数量很大,即使与宇宙中的粒子数量之类的荒唐事物相比也是如此。但是,与无穷大相比,具有任何固定位数的UUID的数量都很少。

使用0xFFFF表示数字结尾标志的问题是,当数字较大时,它会使数字编码效率降低。但是,看来您的UUID方案使此问题更加严重。现在,您将浪费整个UUID空间,而不是跳过256个字节中的一个。计算/识别的效率(而不是空间)在很大程度上取决于您的理论计算机(如果您说的是无穷大,我假设您有)。对于带有磁带和有限状态控制器的TM,无法有效地扩展任何UUID方案(基本上,泵抽引引子使您无法有效地超出固定位长的末端标记)。如果您不假定使用有限状态控制器,则这可能不适用,但是您必须考虑一下位在解码/识别过程中的位置。

如果您只想获得比256个字节中的1个更好的效率,则可以使用将用于UUID方案的1位的任何位长。这是低效率的2 ^位长度中的1。

注意,还有其他编码方案。带分隔符的字节编码恰好是最容易实现的。


2

我建议使用一个字节数组(或整数或长整数)和一个长度字段来说明数字的长度。

这大致是Java的BigInteger使用的方法。由此产生的地址空间是巨大的-轻松地为宇宙中的每个原子赋予不同的UUID :-)

除非您有很好的理由这样做,否则建议您直接使用BigInteger(或其他语言的等效语言)。无需特别发明大号轮。


当字段数可以无限时,不能对数组的长度进行编码。
Slawek 2012年

我同意,在可能的情况下,首选使用现有解决方案(尤其是经过专业审查的解决方案)。谢谢。
德米特里(Dmitri Shuralyov)2012年

@Slawek:是的,但是对于OP描述的用例(即UUID),BigInteger实际上是无限的。无论如何,您都无法在具有有限大小内存的任何计算机中对无限信息进行编码,因此BigInteger与您可能实现的任何其他功能一样好。
mikera 2012年

2

首先,感谢大家为我相对模糊和抽象的问题做出了出色的回答。

在考虑其他答案之后,我想提供一个我已经想到的潜在答案。这不是对所提问题的直接答案,但很重要。

正如某些人指出的那样,使用64/128/256位整数可以为UUID提供很大的空间。显然它不是无限的,但是...

也许仅使用固定大小的int(例如,以64位开始)直到64位不够(或接近64位)可能是一个好主意。然后,假设您具有对所有以前的UUID实例的访问权限,只需将它们全部升级为128位整数,然后将其作为固定大小的整数即可。

如果系统允许这种暂停/中断服务,并且由于这种“重建”操作很少发生,那么好处(非常简单,快速,易于实施的系统)可能会克服缺点(必须重建所有先前分配的整数)到新的整数位大小)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.