我无法理解这个,哪个更随机?
rand()
或者:
rand() * rand()
我发现这是一个真正的脑筋急转弯,你能帮我吗?
编辑:
直觉上我知道数学答案将是它们同样随机,但我不禁认为,如果你“运行随机数算法”两次,当你将两者相乘时,你会创造出比仅仅做更随机的东西一次。
只是一个澄清
尽管每当您尝试发现伪随机变量或其乘法的随机性时,前面的答案都是正确的,但您应该知道,虽然 Random() 通常是均匀分布的,但 Random() * Random() 不是。
例子
这是通过伪随机变量模拟的 uniform random distribution sample:
https://i.stack.imgur.com/M6XTU.png
BarChart[BinCounts[RandomReal[{0, 1}, 50000], 0.01]]
虽然这是将两个随机变量相乘后得到的分布:
https://i.stack.imgur.com/S3Oaa.png
BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] *
RandomReal[{0, 1}, 50000], {50000}], 0.01]]
因此,两者都是“随机的”,但它们的分布非常不同。
另一个例子
虽然 2 * Random() 是均匀分布的:
https://i.stack.imgur.com/XsFWW.png
BarChart[BinCounts[2 * RandomReal[{0, 1}, 50000], 0.01]]
Random() + Random() 不是!
https://i.stack.imgur.com/OyqWF.png
BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] +
RandomReal[{0, 1}, 50000], {50000}], 0.01]]
中心极限定理
Central Limit Theorem 表明随着项数的增加,Random() 的总和趋于 normal distribution。
只需四个术语,您就可以得到:
https://i.stack.imgur.com/VWnJE.png
BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] + RandomReal[{0, 1}, 50000] +
Table[RandomReal[{0, 1}, 50000] + RandomReal[{0, 1}, 50000],
{50000}],
0.01]]
在这里,您可以通过将 1、2、4、6、10 和 20 个均匀分布的随机变量相加来查看从均匀分布到正态分布的道路:
https://i.stack.imgur.com/Apmgz.png
编辑
几个学分
感谢 Thomas Ahle 在评论中指出最后两张图片中显示的概率分布称为 Irwin-Hall distribution
感谢Heike的精彩torn[] function
我猜这两种方法都是随机的,尽管我的直觉会说 rand() * rand()
不那么随机,因为它会播种更多的零。只要一个 rand()
是 0
,总数就变成 0
也不是“更随机”。
rand()
根据伪随机种子(通常基于始终变化的当前时间)生成一组可预测的数字。将序列中的两个连续数字相乘会生成一个不同但同样可预测的数字序列。
解决这是否会减少冲突,答案是否定的。由于在 0 < n < 1
处乘以两个数字的效果,它实际上会增加碰撞。结果将是一个较小的分数,导致结果偏向频谱的低端。
一些进一步的解释。在下文中,“不可预测”和“随机”是指某人根据之前的数字猜测下一个数字将是什么的能力,即。一个神谕。
给定种子 x
,它生成以下值列表:
0.3, 0.6, 0.2, 0.4, 0.8, 0.1, 0.7, 0.3, ...
rand()
将生成上述列表,rand() * rand()
将生成:
0.18, 0.08, 0.08, 0.21, ...
这两种方法总是会为同一个种子产生相同的数字列表,因此同样可以被预言机预测。但是,如果您查看将两个调用相乘的结果,您会发现它们都在 0.3
以下,尽管在原始序列中分布良好。由于两个分数相乘的影响,这些数字是有偏差的。结果数字总是更小,因此尽管仍然不可预测,但更有可能发生碰撞。
rand()+rand()+rand()...
变得越来越“不那么随机”(如果随机意味着均匀分布)。
rand()
实际上是随机的,不要试图“增强”它的随机性。不要多次设置种子。任何单个种子都很好,只要它本身是半随机的。我见过的许多实现都使用 UNIX 纪元作为种子,它每秒都在变化,并且每次变化时都是独一无二的。
过分简化来说明一点。
假设您的随机函数仅输出 0
或 1
。
random()
是 (0,1)
之一,但 random()*random()
是 (0,0,0,1)
之一
您可以清楚地看到,在第二种情况下获得 0
的机会绝不等于获得 1
的机会。
当我第一次发布这个答案时,我希望它尽可能简短,以便阅读它的人一眼就能理解 random()
和 random()*random()
之间的区别,但我无法阻止自己回答原始广告文字问题:
哪个更随机?
由于 random()
、random()*random()
、random()+random()
、(random()+1)/2
或任何其他不会导致固定结果的组合具有相同的熵源(或在伪随机生成器的情况下具有相同的初始状态),答案是它们是同样随机的(区别在于它们的分布)。我们可以看到的一个完美例子是掷骰子游戏。你得到的数字是 random(1,6)+random(1,6)
,我们都知道得到 7 的机会最高,但这并不意味着掷两个骰子的结果比掷一个骰子的结果或多或少是随机的。
这是一个简单的答案。考虑垄断。你掷两个六面骰子(或者对于喜欢游戏符号的人来说是 2d6)并取它们的总和。最常见的结果是 7,因为有 6 种可能的方式可以掷出 7(1,6 2,5 3,4 4,3 5,2 和 6,1)。而 2 只能在 1,1 上滚动。很容易看出滚动 2d6 与滚动 1d12 不同,即使范围相同(忽略您可以在 1d12 上得到 1,点仍然相同)。将结果相乘而不是相加会以类似的方式使它们产生偏差,大多数结果都会出现在范围的中间。如果您试图减少异常值,这是一个好方法,但它无助于均匀分布。
(奇怪的是,它也会增加低掷骰。假设你的随机性从 0 开始,你会在 0 看到一个尖峰,因为它将把另一个掷骰子变成 0。考虑 0 和 1 之间的两个随机数(包括) 和乘法。如果任一结果为 0,则无论其他结果如何,整个事物都变为 0。获得 1 的唯一方法是让两个掷骰都为 1。在实践中,这可能无关紧要但它会产生一个奇怪的图表。)
https://imgs.xkcd.com/comics/random_number.png
以更离散的数字考虑这一点可能会有所帮助。考虑要生成 1 到 36 之间的随机数,因此您决定最简单的方法是掷两个公平的 6 面骰子。你得到这个:
1 2 3 4 5 6
-----------------------------
1| 1 2 3 4 5 6
2| 2 4 6 8 10 12
3| 3 6 9 12 15 18
4| 4 8 12 16 20 24
5| 5 10 15 20 25 30
6| 6 12 18 24 30 36
所以我们有 36 个数字,但并不是所有的数字都得到了公平的体现,有些根本就没有出现。中心对角线附近的数字(左下角到右上角)将以最高频率出现。
描述骰子之间不公平分配的相同原则同样适用于 0.0 到 1.0 之间的浮点数。
关于“随机性”的一些事情是违反直觉的。
假设 rand()
的平坦分布,以下将为您提供非平坦分布:
高偏差:sqrt(rand(range^2))
中间的偏差峰值:(rand(range) + rand(range))/2
低:偏差:范围 - sqrt(rand(range^2))
还有很多其他方法可以创建特定的偏差曲线。我对 rand() * rand()
进行了快速测试,它得到了一个非常非线性的分布。
大多数 rand() 实现都有一段时间。即在大量调用之后,序列重复。 rand() * rand()
的输出序列在一半时间内重复,因此在这个意义上它是“不那么随机的”。
此外,如果不仔细构造,对随机值执行算术往往会导致更少的随机性。上面的一张海报引用了“rand()
+ rand()
+ rand()
...”(例如 k 次),实际上这将趋向于 rand()
返回值范围的平均值的 k 倍。 (这是一个随机游走,其步长与该均值对称。)
具体而言,假设您的 rand() 函数返回 [0,1) 范围内的均匀分布的随机实数。 (是的,这个例子允许无限精度。这不会改变结果。)您没有选择特定的语言,不同的语言可能会做不同的事情,但以下分析适用于任何非反常实现的 rand( )。乘积 rand() * rand()
也在 [0,1) 范围内,但不再均匀分布。事实上,乘积在区间 [0,1/4) 中的可能性与在区间 [1/4,1) 中的可能性一样。更多的乘法会使结果更偏向于零。这使得结果更加可预测。概括地说,更可预测 == 更少随机性。
几乎所有对均匀随机输入的操作序列都是非均匀随机的,从而提高了可预测性。小心,可以克服此属性,但这样会更容易在您实际想要的范围内生成均匀分布的随机数,而不是浪费时间进行算术运算。
“随机”与“更随机”有点像问哪个零更零。
在这种情况下,rand
是 PRNG,因此不是完全随机的。 (事实上,如果种子是已知的,则完全可以预测)。将它乘以另一个值使其不再是随机的。
真正的加密类型 RNG 实际上是随机的。并且通过任何类型的函数运行值都不能为其添加更多熵,并且很可能会消除熵,使其不再随机。
您正在寻找的概念是“熵”,即一串位的无序“程度”。就“最大熵”的概念而言,这个想法最容易理解。
具有最大熵的位串的近似定义是它不能用较短的位串精确地表示(即使用某种算法将较小的字符串扩展回原始字符串)。
最大熵与随机性的相关性源于这样一个事实:如果您“随机”选择一个数字,您几乎肯定会选择一个位串接近具有最大熵的数字,也就是说,它不能被压缩。这是我们对“随机”数字特征的最佳理解。
因此,如果您想从两个随机样本中生成一个随机数,该随机数是“两倍”的随机数,您可以将两个位串连接在一起。实际上,您只需将样本填充到双长字的高半部分和低半部分。
在更实际的情况下,如果您发现自己背负着一个蹩脚的 rand(),它有时可以帮助将几个样本异或在一起——尽管,如果它真的坏了,即使这个过程也无济于事。
4
或二进制 0100
可以压缩为零位。解压程序将简单地返回“4”。它不会比这更随机。 dilbert 的问题是,我们不知道是否可以将其压缩到零位(通过始终返回“九”来解压缩)。它也可能返回 8,然后我们可以压缩到 1 位。减压:0->9,1->8。我们将有 1 个随机位。
接受的答案非常可爱,但是还有另一种方法可以回答您的问题。 PachydermPuncher's answer 已经采用了这种替代方法,我将对其进行一些扩展。
考虑信息论的最简单方法是根据最小的信息单位,一个比特。
在 C 标准库中,rand()
返回 0 到 RAND_MAX
范围内的整数,根据平台的不同,可以定义不同的限制。假设 RAND_MAX
恰好被定义为 2^n - 1
,其中 n
是某个整数(在 Microsoft 的实现中恰好是这种情况,其中 n
是 15)。然后我们会说一个好的实现会返回 n
位信息。
想象一下,rand()
通过掷硬币来构造随机数以找到一位的值,然后重复直到它有一批 15 位。那么位是独立的(任何一个位的值不影响同一批次中其他位具有一定值的可能性)。因此,独立考虑的每个位就像一个介于 0 和 1 之间的随机数,并且在该范围内“均匀分布”(可能是 0 和 1)。
位的独立性确保了由批次位表示的数字也将均匀分布在它们的范围内。这很直观:如果有 15 位,则允许的范围是 0 到 2^15 - 1
= 32767。该范围内的每个数字都是唯一的位模式,例如:
010110101110010
如果这些位是独立的,那么没有任何模式比任何其他模式更可能出现。因此,该范围内所有可能的数字都是同样可能的。所以反过来也是正确的:如果 rand()
产生均匀分布的整数,那么这些数字是由独立的位组成的。
因此,可以将 rand()
视为制造比特的生产线,它恰好以任意大小的批次提供它们。如果您不喜欢大小,请将批次分成单独的位,然后以您喜欢的任意数量将它们重新组合在一起(尽管如果您需要一个不是 2 的幂的特定范围,则需要缩小数字,到目前为止,最简单的方法是转换为浮点数)。
回到您最初的建议,假设您想从 15 个批次变为 30 个批次,向 rand()
询问第一个数字,将其位移 15 个位置,然后再添加一个 rand()
。这是一种组合对 rand()
的两次调用而不会影响均匀分布的方法。它之所以有效,是因为您放置信息位的位置之间没有重叠。
这与通过乘以常数来“拉伸”rand()
的范围非常不同。例如,如果您想将 rand()
的范围加倍,您可以乘以 2 - 但现在您只会得到偶数,而永远不会得到奇数!这并不完全是一个平滑的分配,并且可能是一个严重的问题,具体取决于应用程序,例如,类似于轮盘赌的游戏,据说允许奇数/偶数下注。 (通过考虑位,您可以直观地避免该错误,因为您会意识到乘以 2 与将位向左(更大的意义)移动一位并用零填充间隙相同。所以很明显信息量是一样的——只是移动了一点。)
在浮点数应用程序中无法解决数字范围中的这种差距,因为浮点范围本身就存在根本无法表示的差距:每两个可表示的浮点数之间的差距中存在无限数量的缺失实数点数!因此,无论如何,我们只需要学会忍受差距。
正如其他人所警告的那样,直觉在这个领域是有风险的,特别是因为数学家无法抗拒实数的诱惑,实数令人恐惧地令人困惑,充满了粗糙的无穷大和明显的悖论。
但至少如果你认为它是位的话,你的直觉可能会让你走得更远。比特真的很容易——甚至计算机也能理解它们。
正如其他人所说,简单的简短答案是:不,它不是更随机,但它确实改变了分布。
假设你在玩骰子游戏。你有一些完全公平的随机骰子。如果在每次掷骰之前先将两个骰子放入碗中,摇晃它,随机挑选一个骰子,然后再掷那个骰子,掷骰子会“更随机”吗?显然,这没有什么区别。如果两个骰子都给出随机数,那么随机选择两个骰子中的一个将没有区别。无论哪种方式,您都会得到一个 1 到 6 之间的随机数,并且在足够多的卷上均匀分布。
我想在现实生活中,如果您怀疑骰子可能不公平,这样的程序可能会很有用。例如,如果骰子稍微不平衡,因此一个人倾向于给出 1 的频率高于 1/6,而另一个倾向于不寻常地给出 6,那么在两者之间随机选择往往会掩盖偏差。 (虽然在这种情况下,1 和 6 仍然会超过 2、3、4 和 5。好吧,我想这取决于不平衡的性质。)
随机性有很多定义。随机序列的一个定义是它是由随机过程产生的一系列数字。根据这个定义,如果我掷一个公平的骰子 5 次并得到数字 2、4、3、2、5,那是一个随机序列。如果我再掷同一个公平骰子 5 次并得到 1、1、1、1、1,那么这也是一个随机系列。
几位发帖人指出,计算机上的随机函数不是真正随机的,而是伪随机的,如果你知道算法和种子,它们是完全可以预测的。这是真的,但大多数时候完全无关紧要。如果我洗一副牌,然后一次翻一张,这应该是一个随机系列。如果有人偷看牌,结果将是完全可以预测的,但根据大多数随机性的定义,这不会降低随机性。如果该系列通过了随机性的统计测试,我偷看卡片的事实不会改变这一事实。在实践中,如果我们在你猜下一张牌的能力上赌大笔钱,那么你偷看牌的事实是高度相关的。如果我们使用该系列来模拟我们网站访问者的菜单选择以测试系统的性能,那么您偷看的事实根本没有任何区别。 (只要您不修改程序以利用这些知识。)
编辑
我不认为我可以将我对蒙蒂霍尔问题的回答变成评论,所以我会更新我的答案。
对于那些没有阅读 Belisarius 链接的人,它的要点是:游戏节目参赛者可以选择 3 扇门。一个背后是有价值的奖品,另一个背后是毫无价值的东西。他选择 1 号门。在揭示它是赢家还是输家之前,主持人打开#3 门以表明它是输家。然后,他让参赛者有机会切换到 2 号门。参赛者是否应该这样做?
出乎很多人直觉的答案是,他应该转行。他最初的选择是获胜者的概率是 1/3,另一扇门是获胜者的概率是 2/3。我和许多其他人的最初直觉是,转换不会有任何收获,赔率刚刚改为 50:50。
毕竟,假设有人在主持人打开失败的门后打开了电视。那个人会看到剩下的两扇紧闭的门。假设他知道游戏的性质,他会说每扇门都有 1/2 的机会隐藏奖品。观众的赔率为 1/2 : 1/2 而参赛者的赔率为 1/3 : 2/3 怎么办?
我真的不得不考虑这一点,才能让我的直觉成形。要掌握它,请了解当我们谈论此类问题中的概率时,我们的意思是,您在给定可用信息的情况下分配的概率。对于将奖品放在 1 号门后面的工作人员来说,奖品在 1 号门后面的概率是 100%,而在其他两个门后面的概率为零。
船员的赔率与参赛者的赔率不同,因为他知道参赛者不知道的一些事情,即他把奖品放在了哪扇门后面。同样,参赛者的赔率与观众的赔率不同,因为他知道观众不知道的一些事情,即他最初选择了哪扇门。这不是无关紧要的,因为主人选择打开哪扇门不是随机的。他不会打开参赛者选择的门,也不会打开隐藏奖品的门。如果这些是同一扇门,那他就有两个选择。如果它们是不同的门,则只剩下一个。
那么我们如何得出 1/3 和 2/3 呢?当参赛者最初选择一扇门时,他有 1/3 的机会选择获胜者。我认为这很明显。这意味着有 2/3 的机会其他门之一是赢家。如果主机游戏他有机会在不提供任何额外信息的情况下进行切换,那将没有任何收获。同样,这应该是显而易见的。但一种看待它的方式是说他有 2/3 的机会通过转换获胜。但他有两个选择。所以每个人只有 2/3 除以 2 = 1/3 的机会成为获胜者,这并不比他最初的选择好。当然我们已经知道了最终的结果,这只是另一种计算方式。
但现在主持人透露,这两个选择之一不是赢家。因此,他没有选择的门有 2/3 的机会是赢家,他现在知道 2 个备选方案中的 1 个不是它。另一个可能是也可能不是。所以他不再有 2/3 除以 2。他有 0 表示打开的门,2/3 表示关闭的门。
考虑你有一个简单的硬币翻转问题,其中偶数被认为是正面,奇数被认为是反面。逻辑实现是:
rand() mod 2
在足够大的分布上,偶数的数量应该等于奇数的数量。
现在考虑一个轻微的调整:
rand() * rand() mod 2
如果其中一个结果是偶数,那么整个结果应该是偶数。考虑 4 种可能的结果(偶数 * 偶数 = 偶数,偶数 * 奇数 = 偶数,奇数 * 偶数 = 偶数,奇数 * 奇数 = 奇数)。现在,在足够大的分布上,答案应该是 75% 的时间。
如果我是你,我会打赌。
此评论实际上更多的是解释为什么您不应该根据您的方法实现自定义随机函数,而不是讨论随机性的数学属性。
rand()%2
可能不是很随机;这实际上取决于低位的随机性,而某些 PRNG 并不是那么好。 (当然,在某些语言中,您会从 rand()
中得到浮点结果,因此您根本不能这样做……)
当您对随机数组合会发生什么有疑问时,您可以使用您在统计理论中学到的课程。
在 OP 的情况下,他想知道 X*X = X^2 的结果是什么,其中 X 是沿 Uniform[0,1] 分布的随机变量。我们将使用 CDF 技术,因为它只是一对一的映射。
由于 X ~ Uniform[0,1] 它的 cdf 为: fX(x) = 1 我们想要变换 Y <- X^2 因此 y = x^2 求逆 x(y): sqrt(y) = x this给我们 x 作为 y 的函数。接下来,求导数 dx/dy:d/dy (sqrt(y)) = 1/(2 sqrt(y))
Y 的分布如下: fY(y) = fX(x(y)) |dx/dy| = 1/(2 sqrt(y))
我们还没有完成,我们必须得到 Y 的域。因为 0 <= x < 1, 0 <= x^2 < 1 所以 Y 在 [0, 1) 范围内。如果您想检查 Y 的 pdf 是否确实是 pdf,请将其集成到域:Integrate 1/(2 sqrt(y)) from 0 to 1 上,确实会弹出 1。此外,请注意上述函数的形状看起来像 belisarious 发布的那样。
至于像 X1 + X2 + ... + Xn, (Xi ~ Uniform[0,1]) 这样的东西,我们可以求助于中心极限定理,它适用于任何存在矩的分布。这就是 Z 检验实际存在的原因。
确定生成的 pdf 的其他技术包括雅可比变换(这是 cdf 技术的通用版本)和 MGF 技术。
编辑:作为澄清,请注意我说的是结果转换的分布,而不是它的随机性。这实际上是一个单独的讨论。我实际推导出的也是 (rand())^2。对于 rand() * rand() 它要复杂得多,在任何情况下都不会导致任何种类的均匀分布。
这不是很明显,但 rand()
通常比 rand()*rand()
更随机。重要的是,这对于大多数用途实际上并不是很重要。
但首先,它们产生不同的分布。 如果这是您想要的,这不是问题,但这确实很重要。如果你需要一个特定的分布,那么忽略整个“哪个更随机”的问题。那么为什么 rand()
更随机?
为什么 rand()
更随机(假设它产生范围为 [0..1] 的浮点随机数,这很常见)的核心是,当您将两个 FP 数与大量尾数中的信息,最后会丢失一些信息; IEEE 双精度浮点数中没有足够的位来保存从 [0..1] 中均匀随机选择的两个 IEEE 双精度浮点数中的所有信息,并且这些额外的信息位会丢失。当然,这并不重要,因为您(可能)不会使用该信息,但损失是真实的。您生成哪种发行版也并不重要(即,您使用哪种操作来进行组合)。这些随机数中的每一个(充其量)都具有 52 位的随机信息——这是 IEEE 双精度可以容纳的数量——如果将两个或多个组合成一个,你仍然被限制为最多具有 52 位的随机信息。
大多数随机数的使用甚至没有使用随机源中实际可用的随机性。获得一个好的 PRNG,不要太担心它。 (“好”的程度取决于你用它做什么;在进行蒙特卡洛模拟或密码学时必须小心,否则你可能可以使用标准 PRNG,因为这通常更快。)
通常,浮动随机数基于一种算法,该算法产生一个介于零和某个范围之间的整数。因此,通过使用 rand()*rand(),您实际上是在说 int_rand()*int_rand()/rand_max^2 - 这意味着您排除了任何素数/rand_max^2。
这显着改变了随机分布。
rand() 在大多数系统上是均匀分布的,如果正确播种,很难预测。使用它,除非您有特定的理由对其进行数学运算(即,将分布调整为所需的曲线)。
rand()*rand()
的结果空间(可能值的数量)小于 rand()
的结果空间 - 因为它不包括素数。得到我的投票...
根据您的计算机体系结构,乘以数字最终会在较小的解决方案范围内。
如果您的计算机显示屏显示 16 位 rand()
,则表示 0.1234567890123 乘以第二个 rand()
,0.1234567890123 将得到 0.0152415,如果您重复实验 10^14 次,您肯定会找到更少的解决方案。
大多数这些分布的发生是因为您必须限制或规范化随机数。
我们将其规范化为所有正数,适合某个范围,甚至适合分配的变量类型的内存大小限制。
换句话说,因为我们必须将随机调用限制在 0 和 X 之间(X 是我们变量的大小限制),所以我们将有一组介于 0 和 X 之间的“随机”数字。
现在,当您将随机数添加到另一个随机数时,总和将介于 0 和 2X 之间...这会使值偏离边缘点(将两个小数加在一起和两个大数加在一起的概率非常小你有两个大范围内的随机数)。
想想你有一个接近于零的数字并且你将它与另一个随机数相加的情况,它肯定会变得更大并且远离 0(这对于大数来说是正确的,而且不太可能有两个大数(接近 X 的数字)由 Random 函数返回两次。
现在,如果您要使用负数和正数(在零轴上均匀分布)设置随机方法,情况将不再如此。
比如说RandomReal({-x, x}, 50000, .01)
,那么你会得到一个负数和正数的均匀分布,如果你将随机数加在一起,它们将保持它们的“随机性”。
现在我不确定 Random() * Random()
的负到正跨度会发生什么......这将是一个有趣的图表......但我现在必须回到编写代码。 :-P
没有比这更随机的事情了。它要么是随机的,要么不是随机的。随机意味着“难以预测”。这并不意味着非确定性。如果 random() 是随机的,则 random() 和 random() * random() 都是同样随机的。就随机性而言,分布是无关紧要的。如果出现非均匀分布,则仅意味着某些值比其他值更有可能;它们仍然是不可预测的。由于涉及伪随机性,因此这些数字非常具有确定性。然而,在概率模型和模拟中,伪随机性通常就足够了。众所周知,使伪随机数生成器变得复杂只会使其难以分析。不太可能改善随机性;它经常导致它无法通过统计测试。随机数的所需属性很重要:可重复性和再现性、统计随机性、(通常)均匀分布和大周期是少数。关于随机数的转换:正如有人所说,两个或多个均匀分布的总和导致正态分布。这就是加性中心极限定理。只要所有分布都是独立且相同的,它就适用于任何源分布。乘法中心极限定理说两个或多个独立且一致分布的随机变量的乘积是对数正态的。其他人创建的图表看起来是指数的,但它实际上是对数正态的。所以 random() * random() 是对数正态分布的(尽管它可能不是独立的,因为数字是从同一个流中提取的)。这在某些应用中可能是合乎需要的。但是,通常最好生成一个随机数并将其转换为对数正态分布的数。 Random() * random() 可能难以分析。
有关更多信息,请参阅我在 www.performorama.org 上的书。这本书正在编写中,但相关材料已经在那里。请注意,章节编号可能会随时间而变化。第 8 章(概率论)——第 8.3.1 和 8.3.3 节,第 10 章(随机数)。
实际上,仔细想想,rand() * rand()
比 rand()
随机性少。这就是为什么。
本质上,奇数的数量与偶数的数量相同。并且说 0.04325 是奇数,就像 0.388 是偶数,而 0.4 是偶数,而 0.15 是奇数,
这意味着 rand()
有成为偶数或奇数小数的机会均等。
另一方面,rand() * rand()
的赔率有点不同。让我们说:
double a = rand();
double b = rand();
double c = a * b;
a
和 b
都有 50% 的几率是偶数或奇数。知道
偶数 * 偶数 = 偶数
偶数 * 奇数 = 偶数
奇数 * 奇数 = 奇数
奇数 * 偶数 = 偶数
表示 c
有 75% 的机会 是偶数,而只有 25% 的机会 是奇数,这使得 rand() * rand()
的值比 rand()
更可预测,因此随机性较小。
rand()
通常给出一个介于 0 和 1 之间的数字。谈论它是偶数还是奇数有意义吗?
0.2*0.2=0.04
表明了这种方法的一个根本缺陷:将两个双精度数的 53 位相乘将得到大约 100 位的结果。但是这些位的后半部分将被丢弃。因此,当您以 1 作为其最低有效位的两个双精度数时,您无法说出他们乘积的最低有效位。
rand()
的分布有意义的“偶数”和“奇数”的定义与有意义的“偶数”和“奇数”的定义相同rand()*rand()
的分布。如果不是这样,这个论点就失败了。整数确实如此,但这些不是整数。
使用实现原始多项式的线性反馈移位寄存器 (LFSR)。
结果将是一个 2^n 伪随机数的序列,即没有在序列中重复,其中 n 是 LFSR 中的位数 .... 导致均匀分布。
http://en.wikipedia.org/wiki/Linear_feedback_shift_register http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
使用基于计算机时钟微秒的“随机”种子,或者可能是文件系统中某些不断变化的数据的 md5 结果的子集。
例如,32 位 LFSR 将从给定种子开始按顺序生成 2^32 个唯一数字(没有 2 个相同)。序列将始终保持相同的顺序,但对于不同的种子,起点将不同(显然)。因此,如果种子之间可能重复的序列不是问题,这可能是一个不错的选择。
我使用 128 位 LFSR 在硬件模拟器中使用种子生成随机测试,种子是不断变化的系统数据的 md5 结果。
假设 rand()
返回一个介于 [0, 1)
之间的数字,很明显 rand() * rand()
将偏向 0。这是因为将 x
乘以 [0, 1)
之间的数字会得到一个小于 x
的数字。这是 10000 个更多个随机数的分布:
google.charts.load("current", { packages: ["corechart"] }); google.charts.setOnLoadCallback(drawChart);函数 drawChart() { var i; var 随机数 = []; for (i = 0; i < 10000; i++) { randomNumbers.push(Math.random() * Math.random()); } var chart = new google.visualization.Histogram(document.getElementById("chart-1")); var data = new google.visualization.DataTable(); data.addColumn("数字", "值"); randomNumbers.forEach(function(randomNumber) { data.addRow([randomNumber]); }); chart.draw(data, { title: randomNumbers.length + " rand() * rand() 值在 [0, 1)" 之间,图例:{ position: "none" } }); }
如果 rand()
返回一个介于 [x, y]
之间的整数,那么您有以下分布。注意奇数与偶数的数量:
google.charts.load("current", { packages: ["corechart"] }); google.charts.setOnLoadCallback(drawChart); document.querySelector("#draw-chart").addEventListener("click", drawChart);函数 randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function drawChart() { var min = Number(document.querySelector("#rand-min").value); var max = Number(document.querySelector("#rand-max").value); if (min >= max) { 返回; } 变量我; var 随机数 = []; for (i = 0; i < 10000; i++) { randomNumbers.push(randomInt(min, max) * randomInt(min, max)); } var chart = new google.visualization.Histogram(document.getElementById("chart-1")); var data = new google.visualization.DataTable(); data.addColumn("数字", "值"); randomNumbers.forEach(function(randomNumber) { data.addRow([randomNumber]); }); chart.draw(data, { title: randomNumbers.length + " rand() * rand() 在 [" + min + ", " + max + "]" 之间的值,图例:{ position: "none" },直方图: { bucketSize: 1 } }); }
好的,所以我会尝试通过说您正在创建和使用随机数生成器来添加一些价值来补充其他答案。
随机数生成器是具有多种特征的设备(在非常一般的意义上),可以对其进行修改以适应目的。其中一些(来自我)是:
熵:如香农熵
分布:统计分布(泊松、正态等)
类型:数字的来源(算法、自然事件、组合等)和应用的算法。
效率:执行的速度或复杂性。
模式:周期性、序列、运行等。
可能还有更多……
在这里的大多数答案中,分布是主要的兴趣点,但是通过混合和匹配函数和参数,您可以创建生成随机数的新方法,这些随机数将具有不同的特征,其中一些评估乍一看可能并不明显。
很容易证明两个随机数之和不一定是随机的。想象一下,你有一个 6 面的骰子和掷骰子。每个数字都有 1/6 的机会出现。现在假设您有 2 个骰子并将结果相加。这些总和的分布不是 1/12。为什么?因为某些数字比其他数字出现得更多。其中有多个 partitions。例如数字 2 只是 1+1 的和,但 7 可以由 3+4 或 4+3 或 5+2 等组成……所以它出现的机会更大。
因此,应用变换,在这种情况下,对随机函数进行加法并不会使它更加随机,或者必然保持随机性。在上述骰子的情况下,分布偏斜为 7,因此随机性较小。
正如其他人已经指出的那样,这个问题很难回答,因为我们每个人的脑海中都有自己的随机画面。
这就是为什么,我强烈建议您花一些时间阅读这个网站,以更好地了解随机性:
http://www.random.org/
回到真正的问题。在这个术语中没有或多或少的随机性:
两者都只是随机出现!
在这两种情况下 - 只是 rand() 或 rand() * rand() - 情况都是一样的:在几十亿个数字之后,序列将重复(!)。在观察者看来它是随机的,因为他不知道整个序列,但是计算机没有真正的随机源——所以他也不能产生随机性。
例如:天气是随机的吗?我们没有足够的传感器或知识来确定天气是否随机。
答案将取决于它,希望 rand()*rand() 会比 rand() 更随机,但如下:
两个答案都取决于您的值的位大小
在大多数情况下,您生成取决于伪随机算法(这主要是取决于您的计算机时钟的数字生成器,而不是那么随机)。
使您的代码更具可读性(并且不要用这种咒语调用一些随机的巫毒神)。
好吧,如果您检查上述任何一项,我建议您选择简单的“rand()”。因为您的代码将更具可读性(不会问自己为什么要写这个,因为...嗯...超过 2 秒),易于维护(如果您想用 super_rand 替换您的 rand 函数)。
如果您想要更好的随机性,我建议您从任何提供足够噪音的来源(radio static)流式传输它,然后一个简单的 rand()
就足够了。
不定期副业成功案例分享
rand()+rand()
,你最终会得到一个带有脂肪中心的“2d6”型分布。