随机数,范围为0到n

时间:2009-12-29 00:10:52

标签: algorithm random

给定一个产生真随机32位数的函数R,我想要一个返回0到n范围内随机整数的函数,其中n是任意的(小于2 ^ 32)。

该函数必须以相同的概率产生0到n的所有值。

我想要一个在没有if语句或循环的情况下在常量时间内执行的函数,所以像Java Random.nextInt(n)函数这样的东西就出来了。

我怀疑一个简单的模数不会起作用,除非n是2的幂 - 我是对的吗?


我接受了Jason的答案,尽管它需要一个不确定持续时间的循环,因为它似乎是在实践中使用的最佳方法,并且基本上回答了我的问题。但是我仍然对任何算法感兴趣(即使效率较低),这些算法本质上是确定性的并且保证终止,例如Mark Byers指出的。

5 个答案:

答案 0 :(得分:8)

如果不丢弃源中的某些值,则无法执行此操作。例如,不能将一组大小为2 ^ 32的区域划分为三个大小相等的组。因此,如果不丢弃某些值并迭代直到产生非丢弃值,就不可能这样做。

所以,只需使用此(伪代码):

rng is random number generator produces uniform integers from [0, max)
compute m = max modulo (n + 1)
do {
    draw a random number r from rng
} while(r >= max - m)
return r modulo (n + 1)

实际上,我正在抛弃导致问题的分布的顶部。如果rng上的[0, max)统一,那么此算法将在[0, n]上统一

答案 1 :(得分:3)

你所要求的是不可能的。你不能将2 ** 32个数字分成三组完全相同的大小。

如果你想保证绝对完美的均匀分布在0< = x< n,其中n不是2的幂,那么你必须准备好无数次地调用R.实际上,您通常只需要一两次调用,但理论上代码必须能够多次调用R,否则它不能完全统一。

答案 2 :(得分:0)

我不明白为什么模数不会做你想要的?由于R是一个产生真正的随机32位数的函数,这意味着每个数字具有相同的生成概率,对吧?所以,如果你使用模数n:

randomNumber = R() % (n + 1) //EDITED: n+1 to return values from 0-n

然后从0到n的每个数字具有相同的概率!

答案 3 :(得分:0)

您可以生成两个32位数字并将它们组合在一起形成64位数字。如果不排出数字(如果你需要数字不超过32位),那么最坏的情况可能会偏向0.99999999976716936,这意味着某个数字的概率低于其他数字。

但是如果你仍然想要消除这种小的偏见,那么你将会有低的“超出范围”命中率,在这种情况下会超过1次放电。

答案 4 :(得分:0)

根据您的问题/使用随机数,也许您可​​以使用慢速方法预先分配您的随机数并将它们放入一个简单的数组中。 然后getNextRnd()可以返回数组中的下一个。

快速,固定时间调用,没有分支,只是浪费内存(通常很便宜)和处理初始化时间。

相关问题