生成随机数的方法,基于均匀分布的随机数生成器

3
我被要求使用random(0,1)生成一个在ab之间(包括a和b)的随机数。random(0,1)会生成一个在0和1之间的均匀分布的随机数。请看下面我的答案:
(a+(((1+random(0,1))*b))%(b-a))

我的面试官对我在这个表达式中使用 b 的方式不满意:

(((1+random(0,1))*b))

接着我尝试将我的答案改为:

int*z=(int*)malloc(sizeof(int));
(a+(((1+random(0,1))*(*z)))%(b-a));

后来问题变成了从random(1,5)生成random(1,7)。 我的回答是:

A = rand(1,5)%3
B = (rand(1,5)+1)%3
C = (rand(1,5)+2)%3

rand(1,7) = rand(1,5)+ (A+B+C)%3

我的回答正确吗?

2
请格式化代码,我已经给你示范了。 - Drakosha
1
不需要提及你的潜在雇主。我稍微改了一下你的问题,并进行了格式化,请在继续更新之前考虑审查我的编辑。 - Mark Elliot
rand(1,7) := rand(1,5) 可以正常工作。 - Mateen Ulhaq
类似的问题:https://dev59.com/4XVC5IYBdhLWcg3wcwwm - Dennis Zickefoose
当你说“在a和b之间(包括a和b)”时,是否意味着b是可能的返回值?我猜random(0,1)总是返回小于1的值?这会使得这个问题特别棘手。 - OpenSauce
另外,如果最后一个问题是关于整数随机数生成器而不是浮点随机数生成器,那么它实际上非常棘手。基本上你不能用有限次数的调用random(1,5)来做到这一点,因为没有5的任何幂是7的倍数,所以你永远无法均匀地分配所有可能的随机调用结果给输出。然而,你可以安排预期所需的调用次数相当小(我认为少于3)。对于整数来说,这是一个经典的面试问题,对于浮点数来说,它实际上只是同样的问题。 - Steve Jessop
7个回答

8
我认为你可能将随机整数生成器和随机浮点数生成器混淆了。在C++中,rand()生成介于0和32K之间的随机整数。因此,要生成1到10之间的随机数,我们写rand() % 10 + 1。因此,要生成从整数a到整数b的随机数,我们写rand() % (b - a + 1) + a。
面试官告诉你有一个从0到1的随机生成器。这意味着浮点数生成器。
如何通过数学方法得出答案:
1. 将问题转化为简单形式,使下限为0。 2. 通过乘法缩放范围 3. 再次移动以达到所需范围。
例如:要生成R使其满足:
a <= R <= b.  
Apply rule 1, we get a-a <= R - a <= b-a 
                       0 <= R - a <= b - a.  

将R-a视为R1。如何生成R1,使得R1的范围从0到(b-a)?

R1 = rand(0, 1) * (b-a)   // by apply rule 2.

现在将R1替换为R-a。
R - a = rand(0,1) * (b-a)    ==>   R = a + rand(0,1) * (b-a)

==== 第二个问题 - 不带解释 ====

我们有 1 <= R1 <= 5

==>   0 <= R1 - 1             <= 4
==>   0 <= (R1 - 1)/4         <= 1
==>   0 <= 6 * (R1 - 1)/4     <= 6
==>   1 <= 1 + 6 * (R1 - 1)/4 <= 7

Thus, Rand(1,7) = 1 + 6 * (rand(1,5) - 1) / 4


是的,在生成随机整数时出现了错误。 - badawi
因此,Rand(1,7) = 1 + 6 * (rand(1,5) - 1) / 4。当rand(1,5)只能生成5个输出时,这个方程怎么可能生成7个不同的输出呢? - Terminal
1
我在考虑rand(1,5)生成的是随机实数而不是整数。理论上,rand(1,5)应该在1到5之间(包括1和5)生成无限个随机数。因此,rand(1,7)仍然是一个无限序列的数字。 - badawi
将1-5的随机范围扩展到1-7。 - Terminal

4

从random(0,1)中获取random(a,b):

random(0,1)*(b-a)+a

从random(a,b)中随机选取(c,d):
(random(a,b)-a)/(b-a)*(d-c)+c

或者,针对您的情况进行简化(a=1,b=5,c=1,d=7):
random(1,5) * 1.5 - 0.5

(注:我假设我们谈论的是浮点值,舍入误差可以忽略不计)
注意:此处涉及的是浮点数值,舍入误差可忽略。

2
random(a,b) from random(c,d) = a + (b-a)*((random(c,d) - c)/(d-c))

不需要?

1
不。首先,将[c,d]映射到[0,1],然后将[0,1]映射到[a,b]。你在第一步中缺少了一个“random - c”。 - Dennis Zickefoose
此外,在这里可能会出现栅栏错误;我总是记不住何时应添加一个以获得正确的结束点。 - Dennis Zickefoose
@Dennis:只有当我们讨论整数范围时,栅杆问题才会成为一个问题。 有理数/实数范围的宽度只是端点之间的差异,无论范围是否包括其中一个或两个端点(即范围是否为开放、半开放或封闭)。 只有在整数(或其他非密集集合)中,端点的开放性才会影响范围的长度。 - Steve Jessop

1

[random(0,1)*(b-a)] + a,我认为可以生成a和b之间的随机数。 ([random(1,5)-1]/4)*6 + 1应该在范围(1,7)内生成随机数。 我不确定上述方法是否会破坏均匀分布。


方括号是什么意思? - OpenSauce
@OpenSauce:只是为了方便阅读交替使用括号。 - Dennis Zickefoose

0
我的答案正确吗?
我认为有一些问题。
首先,我假设random()返回一个浮点值 - 否则,使用random(0,1)生成更大范围数字的任何有用分布都需要重复调用以生成一组位来处理。
我还假设C/C++是预期的平台,因为问题被标记为这样。
在这些假设的基础上,你的答案中有一个问题是C/C++不允许在浮点类型上使用%运算符。
但即使我们想象%运算符被替换为使用浮点参数执行模操作的函数,仍然存在一些问题。在你最初的答案中,如果b(或在第二次尝试中分配的未初始化的*z - 我假设这是一种奇怪的获取任意值的方式,或者是其他意图?)为零(假设a和b的给定范围为(-5,0)),那么你的结果将是明显不均匀的。结果将始终为b。

最后,我肯定不是统计学家,但在你的最终答案中(从random(1.5)生成random(1,7)),我相当确定A+B+C会是非均匀的,因此会在结果中引入偏差。


0

我认为这个问题有一个更好的答案。当溢出时,有一个值(概率 ->零),因此模数存在。

  1. 在区间[0,1]中取一个随机数x

  2. 将您的上限增加一个可能是参数的值。

  3. 计算(int(random() / (1.0 / upper_bound)) % upper_bound) + 1 + lower_bound

这应该返回您所需区间内的数字。


-2

给定random(0,5),你可以通过以下方式生成random(0,7)

A = random(0,5)*random(0,5) 现在A的范围是0-25

如果我们简单地对A取模7,我们可以得到随机数,但它们不会真正随机,因为对于A的值在22-25之间,取模操作后会得到1-4的值,因此从范围(0,25)中获取模7会偏向于1-4。这是因为7不能均匀地除以25:小于或等于25的最大7的倍数是7*3=21,而在21-25的不完整范围内的数字将导致偏差。

解决这个问题最简单的方法是丢弃那些数字(从22-25),并继续尝试,直到出现适当范围内的数字。

显然,这仅适用于我们想要随机整数的情况。

然而,要获得随机浮点数,我们需要根据上述帖子中描述的方式修改范围。


1
为什么两个均匀随机数的乘积也是均匀分布?即使你以离散均匀分布为例,你也可以很容易地看出在范围0..25内有一些数字是永远不可能得到的,比如质数。因此,结果绝不是另一个均匀分布。顺便说一下,即使是这样的随机变量之和也不行。想想两个独立骰子的总和。 - Jens Gustedt
1
这几乎是正确的均匀随机整数技术,但不完全正确。应该是A = random(0,4) + 5 * random(0,4),其中端点在我的“random”函数中是包括的,正如提问者所述。当然,random(0,4)只是random(1,5) - 1。然后您可以重试最后几个值,并按此处所述取A模7。 - Steve Jessop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接