Math 访谈:使用random2实现random3功能

Math 访谈:使用random2实现random3功能,math,random,statistics,Math,Random,Statistics,在最近的采访中,我被问到以下问题。有一个函数random2(),它以相等的概率(0.5)返回0或1。使用random2()编写random4()和random3()的实现。 像这样实现random4()很容易 if(random2()) return random2(); return random2() + 2; 但是我在random3()方面遇到了困难。我唯一能代表的认识是: uint32_t sum = 0; for (uint32_t i = 0; i != N; ++i) s

在最近的采访中,我被问到以下问题。有一个函数
random2()
,它以相等的概率(0.5)返回0或1。使用
random2()
编写
random4()
random3()
的实现。 像这样实现
random4()
很容易

if(random2())
  return random2();
return random2() + 2;
但是我在
random3()
方面遇到了困难。我唯一能代表的认识是:

uint32_t sum = 0;
for (uint32_t i = 0; i != N; ++i)
  sum += random2();
return sum % 3;

random4()
的这个实现仅仅基于我的直觉。我不确定它实际上是否正确,因为我无法从数学上证明它的正确性。谁能帮我解答这个问题。

random 3:

不确定这是否是最有效的方法,但我的看法是:

x=random2+2*random2

可能发生的情况:

0 + 0 = 0
0 + 2 = 2
1 + 0 = 1
1 + 2 = 3
以上是所有可能发生的事情的可能性,因此每个都有相同的概率,所以

p(x=c)
是x=c的概率)

现在,当x=3时,我们继续生成另一个数,从而使0,1,2的概率相等。更严格地说,你可以将x=3的概率分布到所有这些概率中,这样p(x=3)趋于0,因此其他概率将趋于0.33

代码:

random4:

让我们浏览一下您的代码:

if(random2())
  return random2();
return random2() + 2;
第一次调用有50%的概率为1(true)=>返回0或1,概率为50%*50%,因此每个返回25%

第一次调用有50%的几率为0(false)=>以50%*50%的概率返回2或3,因此每个返回25%

因此,您的代码以相同的概率生成0,1,2,3

受E4F4答案启发的更新:

对于一个比我上面提供的更确定的答案

通过多次调用
random2
生成一些大数字,并根据所需数字修改结果

这对每一个都不是完全正确的概率,但会很接近

因此,对于通过调用
random2
32次得到的32位整数,target=3:

总数:4294967296
x的数量,使得x%3=1或2:1431655765
x的数量,使得x%3=0:1431655766
1或2的概率(每个):0.33333325572311878204345703125
0的概率:0.3333334885537624359130859375

所以在0.00000002%的正确概率内,看起来非常接近

代码:

sum=0;
对于(int i=0;i<32;i++)
sum=2*sum+random2();
返回和%N;
注意:

正如pjr所指出的,一般来说,这种方法的效率远远低于上述的拒绝方法。使用拒绝方法获得相同数量的
random2
(即32次)(假设这是最慢的操作)调用的概率为
0.25^(32/2)=0.0000000002=0.00000002%
。再加上这种方法不精确的事实,让我们更倾向于拒绝方法。降低这个数字会减少运行时间,但会增加错误,并且可能需要将其降低很多(从而达到高错误),以接近拒绝方法的平均运行时间

值得注意的是,上述算法有一个最长的运行时间。拒绝方法不适用。如果您的随机数生成器因某种原因完全损坏,它可能会继续生成被拒绝的数字,并使用拒绝方法运行相当长一段时间或永远,但无论发生什么情况,上面的for循环都将运行32次。

不建议使用模(
%
)因为它会引入偏差。只有当
n
2
的幂时,映射才会很好。否则,如其他答案所示,会涉及某种拒绝

另一种通用方法是通过以下方式模拟内置PRNG——

  • 生成32
    random2()
    并将其映射到32位整数
  • 用最大整数值除以范围
    (0,1)
    中的随机数
  • 只需将该数字乘以
    n
    (=3,4…73等等)和
    floor
    ,即可获得所需的输出

对于我们中间的dim,什么是
random4()
random3()
应该返回?在
For
循环中
N
是什么?@HighPerformanceMark我猜
randomN()
应该返回
0,1,2,。。。,N-1
的概率相等。@杜克林:是的,你是对的。@高性能标记生成32位随机数的非常有趣的解决方案。我喜欢,谢谢。拒绝比打32次随机电话要有效得多。在每次迭代中,您有3/4的停止概率和1/4的拒绝和循环概率。从长远来看,您将在平均4/3次迭代后终止,并需要8/3次调用random2,加上结果的准确概率将是1/3,而不是近似概率。@pjs有用的注释。已编辑。@Dukeling拒绝方法的长期运行时间意味着random2不符合其规范p(0)=p(1)=1/2。你是对的,32呼叫版本是有界的,但我愿意冒2E-10的机会,超过单个呼叫的界限。如果我们讨论一系列调用,拒绝序列比有界序列长的概率很快接近概率范围,即我身体中的所有原子绕过地板上的所有原子,我最终进入地下室。我不会担心的。
do
  val = random2() + 2*random2();
while (val != 3);
return val;
if(random2())
  return random2();
return random2() + 2;
sum = 0;
for (int i = 0; i < 32; i++)
  sum = 2*sum + random2();
return sum % N;