如何使用错误的生成器获取随机数

时间:2011-10-08 05:04:16

标签: objective-c algorithm random

问题:假设您有一个随机数生成器randn(),它返回0到n-1之间的均匀分布的随机数。给定任意数m,写一个随机数生成器,返回0到m-1之间均匀分布的随机数。

我的回答:

-(int)randm() {
    int k=1;
    while (k*n < m) {
        ++k;
    }
    int x = 0;
    for (int i=0; i<k; ++i) {
        x += randn();
    }
    if (x < m) {
        return x;
    } else {
        return randm();
    }
}

这是对的吗?

4 个答案:

答案 0 :(得分:9)

你很接近,但你的答案的问题在于,有一种方法可以将一个数字写成另外两个数字的总和。

如果m<n,那么这是有效的,因为数字0,1,...,m-1每个都有相同的概率,算法几乎肯定会终止。

这个答案一般不起作用,因为将一个数字写成两个其他数字之和的方法不止一种。例如,只有一种方法可以获得0,但有许多方法可以获得m/2,因此概率不会相等。

示例n = 2m=3

0 = 0+0
1 = 1+0 or 0+1
2 = 1+1

所以你方法的概率分布是

P(0)=1/4
P(1)=1/2
P(2)=1/4

这不统一。


要解决此问题,您可以使用唯一分解。在基础m中写下n,跟踪所需的最大指数,例如e。然后,找到小于m的{​​{1}}的最大倍数,将其称为n^e。最后,使用k生成e个数字,将其作为某个数字randn()的基础n扩展,如果x,则返回x < k*m,否则再试一次。

假设x,那么

m < n^2

答案 1 :(得分:4)

这不正确。

您正在添加统一的随机数,这不会产生一致的随机结果。假设n = 2且m = 3,则x的可能值为0 + 0,0 + 1,1 + 0,1 + 1。所以得到1的可能性是获得0或2的两倍。

您需要做的是在基数n中写入m,然后生成随机数的基数n表示的“数字”。如果您有完整的号码,则必须检查它是否小于m。如果是,那么你就完成了。如果不是,那么你需要重新开始。

答案 2 :(得分:3)

两个均匀随机数发生器的总和不是均匀生成的。例如,两个骰子的总和更可能是7比12,因为得到12你需要投掷两个六,而你可以得到7作为1 + 6或6 + 1或2 + 5或5 + 2或...

假设randn()返回0到n - 1之间的整数,n * randn()+ randn()均匀分布在0和n * n - 1之间,因此可以增加其范围。如果randn()返回一个介于0和k * m + j - 1之间的整数,则重复调用它直到得到一个数字&lt; = k * m - 1,然后将结果除以k得到一个均匀分布的数字0和m -1。

答案 3 :(得分:0)

假设n和m都是正整数,那么缩放的标准算法是否会起作用?

return (int)((float)randn() * m / n);