问题 如何实现只有Random(0,1)的Random(a,b)? [重复]


可能重复:
如何通过已知的均匀随机函数RANDOM(0,1)在a,b之间得到均匀随机 

在书中 算法简介,有一个消费税:

描述只调用Random(0,1)的过程Random(a,b)的实现。作为a和b的函数,您的程序的预期运行时间是多少? Random(a,b)结果的概率应该是纯粹均匀分布的,如Random(0,1)

对于Random函数,结果是a和b之间的整数,包括在内。例如,Random(0,1)生成0或1;随机(a,b)生成a,a + 1,a + 2,...,b

我的解决方案是这样的:

for i = 1 to b-a
    r = a + Random(0,1)
return r

运行时间是 T = B-A

它是否正确?我的解决方案的结果是否均匀分布?

谢谢

如果我的新解决方案如下所示:

r = a
for i = 1 to b - a //including b-a
    r += Random(0,1)
return r

如果不正确,为什么r + = Random(0,1)使r不均匀分布?


7004
2018-01-01 11:10


起源

您的解决方案不是均匀分布的。作为最低值的例子 a 只能通过随机(0)+随机(0)+随机(0)+的总和来“计算”......但是“中间”值的概率更高,因为它可以计算为0+ 0 + 0 + 1 + 1,0 + 0 + 1 + 0 + 1,以及1 + 1 + 0 + 0 + 0,依此类推。把它想象成扔2个骰子。得到2(1 + 1)或12(6 + 6)的概率低于得到7(1 + 6,2 + 5,3 + 4,4 + 3,5 + 2,6 + 1)的概率(catan ftw。的定居者;))。 - Progman
你的第二行重置 r 每一次。你应该初始化它 a然后在循环中根据自身更新它。 - Matthew Strawbridge


答案:


其他人解释了为什么你的解决方案不起作用。这是正确的解决方案:

1)找到最小的数字, p这样的 2^p > b-a

2)执行以下算法:

r=0
for i = 1 to p
    r = 2*r + Random(0,1)

3)如果 r 大于 b-a,转到第2步。

4)你的结果是 r+a

那么让我们试试随机(1,3)。
所以 b-a 是2。
2^1 = 2所以 p 必须是2才这样 2^p 大于2。
所以我们将循环两次。让我们尝试所有可能的输出:

00 -> r=0, 0 is not > 2, so we output 0+1 or 1.
01 -> r=1, 1 is not > 2, so we output 1+1 or 2.
10 -> r=2, 2 is not > 2, so we output 2+1 or 3.
11 -> r=3, 3 is > 2, so we repeat.

所以1/4的时间,我们输出1. 1/4我们输出的时间2. 1/4我们输出的时间3.而1/4的时间我们必须再次重复算法。看起来不错。

请注意,如果您必须执行此操作,则可以使用两个优化:

1)如果你经常使用相同的范围,有一个计算的类 p 一旦这样你就不必每次都计算它。

2)许多CPU具有执行步骤1的快速方法,这些方法未在高级语言中公开。例如,x86 CPU有 BSR 指令。


13
2018-01-01 11:42



所以这里的想法是找到表示最高数字所需的最大位数,然后只为每个位翻转硬币。 - Christian Neverdal
是。然后,如果它超出范围,重复该过程。 - David Schwartz
来自类似的东西,而不是二元搜索的形式。谢谢,很高兴看到它没关系。希望能以一种聪明的方式将问题从2的幂减少到任何数量(并且更好的O-big)。 - gorlum0


不,这不正确,该方法将集中精力 (a+b)/2。这是一个二项分布。

你确定吗? Random(0,1) 产生整数?如果它产生0到1之间的浮点值,那将更有意义。然后解决方案将是仿射变换,运行时间独立于 a 和 b

我刚才有一个想法,如果它是关于整数值:使用二分法。在每一步,你都有一个范围 low-high。如果 Random(0,1) 返回0,下一个范围是 low-(low+high)/2否则 (low+high)/2-high。 细节和复杂性留给你,因为它是功课。

这应该创造(近似)均匀分布。

编辑:   是那里的重要词汇。制服如果 b-a+1 是2的幂,如果接近则不太远,但一般不够好。啊,这是一个自发的想法,不能让他们没事。


2
2018-01-01 11:19



以下是本书的引用:我们假设我们拥有一个随机数发生器RANDOM。对RANDOM(a,b)的调用返回a和b之间的整数,包括在内,每个这样的整数同样可能。例如,RANDOM(0,1)以概率1/2产生0,并且以概率1/2产生1 - Ivaylo Strandjev
啊哈。对,否则本来就太容易了。当我看到家庭作业标签时,我忘记了第一行:) - Daniel Fischer
@DanielFischer这只会产生近似均匀的分布。考虑(1,3)。 - David Schwartz
是的,只对2的力量完美。但对于一个自发的想法来说并不太蹩脚。 - Daniel Fischer


我读了其他的答案。为了好玩,这是找到随机数的另一种方法:

使用分配数组 b-a 元素。 将所有值设置为 1。 遍历数组。对于每个非零元素,按原样翻转硬币。如果它出现了 0,将元素设置为 0

每当完成一次迭代后,你只剩下1个元素,你就得到了你的随机数: a+i 哪里 i 是非零元素的索引(假设我们开始索引 0)。那么所有数字都是同样可能的。 (你必须处理它是一个平局的情况,但我把它作为练习留给你。)

这会有 O(infinity) ...... :) 但平均而言,一半的数字将被消除,因此它的平均案例运行时间为 log_2 (b-a)


1
2018-01-01 11:56



你实际上可以合理地完成这项工作,如果你做得对,那就是O(n log n)(其中n = b-a)。基本上,如果Random(0,1)为1,您希望递增每个数组元素,如果它的值小于截止值,则考虑运行中的每个元素。您在每次传递后增加截止值,如果没有值有效,则减少截止值。当一个条目有效时,您就完成了。 - David Schwartz


首先,我假设您实际上正在累积结果,而不是在每一步上添加0或1。 使用一些概率可以证明您的解决方案不是均匀分布的。结果值r为(a + b)/ 2的可能性最大。例如,如果a为0且b为7,则获得值4的机会是(7的组合4)除以2提升到7的幂。原因是无论7个值中的哪4个值是1,结果仍然是4。

您估计的运行时间是正确的。


0
2018-01-01 11:22





在您创建的算法中,它实际上并不是均匀分布的。

结果“r”将始终为“a”或“a + 1”。它永远不会超越它。

它应该看起来像这样:

r=0;
for i=0 to b-a
   r = a + r + Random(0,1)

return r;

通过在计算中包含“r”,您可以包含所有先前“for”循环运行的“随机性”。


0
2018-01-01 11:26





不,您的解决方案不正确。这个总和将具有二项分布。

但是,您可以生成0,1的纯随机序列,并将其视为二进制数。

repeat
  result = a
  steps = ceiling(log(b - a))

  for i = 0 to steps
    result += (2 ^ i) * Random(0, 1)
until result <= b

KennyTM:我的坏。


0
2018-01-01 11:41



2 ^ (i * Random(0, 1))?你的意思是 (2 ^ i) * Random(0, 1)? - kennytm


您的解决方案的伪代码应如下所示:

r=a
for i = 0 to b-a
    r+=Random(0,1)
return r

至于均匀分布,假设该随机数发生器基于的随机实现是完全一致的,获得0或1的几率是50%。因此,获得您想要的数字是一遍又一遍的选择的结果。

因此,对于a = 1,b = 5,有5个选择。

获得1的几率涉及5个决定,均为0,其可能性为0.5 ^ 5 = 3.125%

获得5的几率涉及5个决定,全部为1,其可能性为0.5 ^ 5 = 3.125%

从中可以看出,分布不均匀 - 任何数字的几率应为20%。


-1
2018-01-01 11:22