Random 如何在恒定时间内生成无偏随机bigint
在我的嵌入式项目中,我有一个处理任意长度整数的biginteger类。我希望能够生成一个介于0和任意数之间的随机bigint。假设我有一个高质量的随机字节源 我看到的所有实现基本上都做了相同的事情:Random 如何在恒定时间内生成无偏随机bigint,random,language-agnostic,real-time,bigint,Random,Language Agnostic,Real Time,Bigint,在我的嵌入式项目中,我有一个处理任意长度整数的biginteger类。我希望能够生成一个介于0和任意数之间的随机bigint。假设我有一个高质量的随机字节源 我看到的所有实现基本上都做了相同的事情: 生成具有正确字节数的大数字 如果大于最大值,请重新生成 我看到这个实现的问题是它可能需要非常长的时间。想象一下max=2^2049-1=(01 FF..FF)。此算法将生成257个字节,然后检查最高有效字节是否为。如果您的任意最大数为2减1的幂,则可以使用随机位源(例如掷硬币)来填充位。这给出了一个
我看到这个实现的问题是它可能需要非常长的时间。想象一下
max=2^2049-1
=(01 FF..FF
)。此算法将生成257个字节,然后检查最高有效字节是否为。如果您的任意最大数为2减1的幂,则可以使用随机位源(例如掷硬币)来填充位。这给出了一个均匀分布的数字。您可以使用高质量的RNG以32或64为一组生成位,并无偏差地截断最后一个字
现在,如果你的任意最大数不是2减1的幂,那么使用上面的技术在0..1范围内创建一个均匀分数。分数使用的位数越多,结果中的偏差就越小
例如,调用您的任意最大号码M
,选择一个n
,以便
2^n >> M /* 2^n is much greater than M */
现在,你的随机数是
M * (rand(2^n) / 2^n)
其中,rand
是上面第一段中描述的过程。随机数生成器创建具有整数位数的随机数。如果数字在统计上确实是随机的,那么每个位都独立于其他位,您可以使用或丢弃它们的任何组合。例如,您可以简单地丢弃7位,得到一个无偏差的数字
对于不是2的幂的范围,您可以将范围的大小因子化,并为每个范围获取一个随机数,然后将它们合并。如果我们假设一个函数randint(n)
,它提供了一个介于0
和n-1
之间的无偏随机数,则一般公式为:
(((randint(A) * B + randint(B)) * C + randint(C)) * D + randint(D)) ...
例如,如果您的范围是0-10^616-1
,则可以将其分解为5^616*2^616
rand_10_616 = randint(5^616) * 2^616 + randint(2^616)
显然,要获得5^616
的无偏结果仍然存在问题,但这是一个需要解决的较小问题。答案是,通常不可能在[0,n
)在恒定时间内。一个值得注意的例外是当RNG产生随机位时,n
是2的幂
例如,假设RNG是一个“真”随机发生器,可以产生无偏随机位。然后,除非n
是2的幂,否则只有两种可能的方法进行:
- 它可以使用模约化(或Lemire的乘法然后移位约化)。这将在恒定时间内运行,但会引入偏差(一些数字比其他数字更可能生成)
- 它可以使用拒绝采样。这不会引入偏差,但可以在最坏的情况下永远运行(即使它具有预期的恒定时间复杂度)。许多类型的算法都适用于这一类别,包括模降阶和拒绝步骤(如果
n
不是2的幂次方,这是必要的),以及(使用随机位)
(有关这两种算法的概览,请参见我的章节“”
在这个意义上,Knuth和Yao在1976年证明,任何只使用随机位产生给定概率的随机整数的算法都可以表示为二叉树,其中随机位表示遍历树的方式,每个叶(端点)对应一个结果。在这种情况下,[0,n]中的每个整数可能以1/n的概率发生。如果1/n具有非终止的二进制扩展(如果n
不是2的幂,则会出现这种情况),则该二叉树也必然-
- 具有“无限”深度,或
- 包括树末端的“拒绝”叶子
无论哪种情况,算法都不会在固定时间内运行
模或类似的约化相当于一个二叉树,其中拒绝叶被标记的结果所取代,但由于可能的结果比拒绝叶更多,因此只有一些结果可以取代拒绝叶,从而引入偏差。相同类型的二叉树和相同类型的偏差如果经过一定次数的迭代后停止拒绝,则结果为(另见L.Devroye,1986年《非均匀随机变量生成》第15章)
因此:通常,整数生成器可以是无偏时间,也可以是常数时间,但不能同时是无偏时间和常数时间
如果你不能忍受永远运行的最坏情况,那么你唯一能做的就是设置一个固定的最大拒绝次数或使用减少,这两者都会引入偏差。但是,根据你的应用程序,这种偏差可能可以忽略不计(例如,如果算法“失败”的几率与它失败的几率相比可以忽略不计“成功”,用于应用程序目的)。生成随机整数还有一些安全方面,这太复杂了,无法在本回答中讨论。我不认为仅重新生成部分字节会产生偏差。您只是用其他随机字节替换一些随机字节。本质上,您的问题归结为在0和255之间选择n个随机数,a一个较低范围的随机数。对我来说似乎是一个简单而明显的解决方案。另一方面,右移会引入偏差,在你的例子中,你永远不会将数字右移到00或01。这个答案的第一段是绝对正确的。其余部分是错误的,因为它不能消除偏差。当你你认为<代码> m <代码>将是一个非常大的数字。R:消除偏见,通过增加<代码> N<代码>我相信你可以红色。