【问题标题】:How to generate an unbiased random bigint in constant time如何在恒定时间内生成无偏随机 bigint
【发布时间】:2016-01-22 03:35:28
【问题描述】:

在我的嵌入式项目中,我有一个处理任意长度整数的 biginteger 类。我希望能够生成一个介于 0 和任意数字之间的随机 bigint。假设我有一个随机字节的质量来源。

我见过的所有实现基本上都是做同样的事情:

  1. 用正确的字节数生成一个大数,
  2. 如果大于最大值,则重新生成。

我看到这个实现的问题是它可能需要很长时间。想象一下max = 2^2049-1 =(01 FF .. FF)。该算法将生成 257 个字节,然后检查最高有效字节是否为<=1。所以它有 254/256 的机会必须生成一个全新的 257 字节数。在(当然不太可能)最坏的情况下,这个循环可能会持续数分钟或数年。

我的问题是:
在生成的数字太大的情况下,有没有办法保留我已经生成的大部分字节?
只重新生成最重要的字节是否有效,还是会引入偏差?将结果右移一位怎么样?

有什么方法可以使时间确定,同时又避免偏差?

--

另一种极端情况:max = 2^2048 + 1 = (01 00 .. 01) 在这种情况下,如果剩余字节为 0,后跟 0001,则最高有效字节可以为非零。因此,大多数情况下,如果 MSB 不为零,则它将无效,并且仅重新生成该字节将永远不会使其有效。但是仅仅强制将其设置为零似乎也是错误的。

【问题讨论】:

  • 我不明白只重新生成部分字节会如何引入偏差。您只是用其他随机字节替换一些随机字节。本质上,您的问题归结为选择 0 到 255 之间的 n 个随机数,以及一个范围较小的随机数。对我来说似乎是一个简单而明显的解决方案。另一方面,右移会引入偏差,在您的示例中,您永远不会用 00 或 01 右移数字

标签: random language-agnostic real-time bigint


【解决方案1】:

如果您的任意最大数是 2 减一的幂,则可以使用随机位源(例如掷硬币)来填充位。这给出了一个均匀分布的数字。您可以使用高质量的 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 是上面第一段中描述的过程。

【讨论】:

  • 这个答案的第一段是绝对正确的。其余的都是错误的,因为它没有消除偏见。当您考虑到M 将是一个非常大的数字时,这也是不切实际的。
  • Re: 消除偏差,通过增加n 我相信你可以将偏差降低到源RNG以下,无论如何,任意小。回复:实用性,只有在有明确要求的情况下才能进行测试。唯一的要求是时间确定性,这个算法当然满足。无论如何,代码都在处理大小为 M 的数字;额外的乘法和移位可能没有那么重要!
【解决方案2】:

随机数生成器创建具有整数位数的随机数。如果该数字在统计上是真正随机的,那么每个位都独立于其他位,您可以使用或丢弃它们的任何组合。对于您的示例,您可以简单地丢弃 7 位并获得一个无偏数。

对于不是 2 的幂的范围,您可以考虑范围的大小并为每个范围获取一个随机数,然后将它们组合起来。如果我们假设一个函数randint(n) 提供一个介于0n-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 的无偏结果,但这是一个需要解决的小问题。

【讨论】:

  • 范围不保证是 2 的幂。如果我可以factor bigints efficiently,那是不是意味着我已经破解了 RSA?
  • @AShelly 是的,确实会。由于您从未指定如何获得随机数限制,因此无法知道此答案是否相关。
【解决方案3】:

答案是,通常不可能在恒定时间内在 [0, n) 中生成随机无偏整数。一个值得注意的例外是当 RNG 产生随机位并且n 是 2 的幂时。

例如,假设 RNG 是“真正的”随机生成器,并且可以生成无偏随机位。那么,除非n 是 2 的幂,否则只有两种可能的方法:

  • 它可以使用模归约(或 Lemire 的乘法然后移位归约)。这将在恒定时间内运行,但会引入偏差(某些数字比其他数字更容易生成)。
  • 它可以使用拒绝抽样。这不会引入偏差,但在最坏的情况下可以永远运行(即使它具有预期的恒定时间复杂度)。很多类型的算法都属于这一类,包括模约归约和拒绝步骤(如果 n 不是 2 的幂,则这是必要的),以及 Fast Dice Roller(使用随机位)。

(有关这两种算法的调查,请参阅我的部分“A Note on Integer Generation Algorithms”。)

从这个意义上说,Knuth 和 Yao 在 1976 年表明,任何仅使用随机位以给定概率生成随机整数的算法都可以表示为二叉树,其中随机位指示遍历树的方式和每个叶(端点)对应一个结果。在这种情况下,[0, n) 中的每个整数都可以以 1/n 的概率出现。如果 1/n 有一个非终止的二元展开式(如果n 不是 2 的幂,就会出现这种情况),这棵二叉树必然会——

  • 具有“无限”深度,或
  • 在树的末端包含“拒绝”叶子,

在任何一种情况下,算法都不会在恒定时间内运行。

模数或类似的缩减相当于一棵二叉树,其中拒绝叶被标记的结果替换 - 但由于可能的结果比拒绝叶更多,因此只有一些结果可以代替拒绝叶,从而引入偏差.如果您在一定次数的迭代后停止拒绝,则会产生相同类型的二叉树 - 以及相同类型的偏差。 (另见 L. Devroye,1986 年的非均匀随机变量生成的第 15 章。)

因此:一般来说,整数生成器可以要么无偏恒定时间,但不能两者兼而有之。

如果您不能容忍永远运行的最坏情况,那么您唯一能做的就是设置一个固定的最大拒绝数或使用减少,这两者都会引入偏见。但是,根据您的应用程序,这种偏差可能可以忽略不计(例如,对于应用程序的目的,如果算法“失败”的机会与它“成功”的机会相比可以忽略不计)。随机整数生成也有安全方面的问题,在这个答案中讨论太复杂了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 2017-07-13
    • 1970-01-01
    • 2012-01-26
    相关资源
    最近更新 更多