关于数学:理解“随机性”

Understanding “randomness”

我没办法解决这个问题,哪一个更随意?

1
rand()

1
rand() * rand()

我觉得这是一个真正的脑筋急转弯,你能帮我一下吗?

编辑:

直觉上,我知道数学上的答案是,它们都是随机的,但我忍不住想,如果你把两个数相乘时"运行随机数算法"两次,你会创造出比只做一次更随机的结果。


只是澄清一下

尽管前面的答案是正确的,但当您试图发现伪随机变量或其乘法的随机性时,您应该注意,尽管random()通常是均匀分布的,random()*random()则不是。

例子

这是通过伪随机变量模拟的均匀随机分布样本:

Histogram of Random()

1
        BarChart[BinCounts[RandomReal[{0, 1}, 50000], 0.01]]

当这是两个随机变量相乘后得到的分布:

Histogram of Random() * Random()

1
2
        BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] *
                                 RandomReal[{0, 1}, 50000], {50000}], 0.01]]

所以,两者都是"随机的",但是它们的分布是非常不同的。

另一个例子

而2*Random()是均匀分布的:

Histogram of 2 * Random()

1
        BarChart[BinCounts[2 * RandomReal[{0, 1}, 50000], 0.01]]

Random()+Random()不是!

Histogram of Random() + Random()

1
2
        BarChart[BinCounts[Table[RandomReal[{0, 1}, 50000] +
                                 RandomReal[{0, 1}, 50000], {50000}], 0.01]]

中心极限定理

中心极限定理指出,随着项的增加,随机数的和趋于正态分布。

只有四个学期:

Histogram of Random() + Random() + Random() + Random()

1
2
3
4
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个均匀分布的随机变量,看到从均匀分布到正态分布的道路:

Histogram of different numbers of random variables added

编辑

几学分

多亏了托马斯·艾尔在评论中指出,最后两幅图像中显示的概率分布被称为欧文·霍尔分布。

感谢海克出色的撕裂功能


我想这两种方法都是随机的,尽管我的直觉会说rand() * rand()的随机性较小,因为它会产生更多的零。一个rand()0时,总数就变成0


两者都不是"更随机的"。

rand()根据psuedo随机种子生成一组可预测的数字(通常基于当前时间,这总是在变化)。将序列中的两个连续数字相乘会生成一个不同但同样可预测的数字序列。

解决这是否会减少碰撞问题,答案是否定的。它实际上会增加碰撞,因为在0 < n < 1中乘以两个数字的效果。结果将是一个较小的分数,导致结果偏向频谱的低端。

一些进一步的解释。在下文中,"不可预测"和"随机"指的是某人根据之前的数字猜测下一个数字的能力,即甲骨文。

给定种子x,生成以下值列表:

1
0.3, 0.6, 0.2, 0.4, 0.8, 0.1, 0.7, 0.3, ...

rand()生成上述列表,rand() * rand()生成:

1
0.18, 0.08, 0.08, 0.21, ...

这两种方法总是为相同的种子生成相同的数字列表,因此Oracle同样可以预测。但是,如果您查看两个调用相乘的结果,您会发现它们都在0.3下,尽管它们在原始序列中的分布很好。由于两个分数相乘的影响,这些数字是有偏的。结果数字总是较小的,因此更可能是一个碰撞,尽管仍然是不可预测的。


过于简单化以说明一点。

假设您的随机函数只输出01

random()(0,1)中的一个,而random()*random()(0,0,0,1)中的一个。

你可以清楚地看到,在第二种情况下,获得0的机会决不等于获得1的机会。

当我第一次发布这个答案时,我希望尽可能的简短,这样一个阅读它的人一眼就能理解random()random()*random()之间的区别,但我不能阻止自己回答最初的ad litteram问题:

哪个更随机?

如果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、3、5、2和6、1)。而2只能在1,1上滚动。很容易看出滚动2d6与滚动1d12不同,即使范围相同(忽略在1d12上可以得到1,点保持不变)。将结果相乘而不是相加将以类似的方式扭曲它们,其中大多数结果都位于范围中间。如果你试图减少异常值,这是一个很好的方法,但它不会有助于实现均匀分布。

(奇怪的是,它也会增加低辊。假设你的随机性从0开始,你会看到一个尖峰在0,因为它会把其他的掷骰变成0。考虑两个介于0和1(包括0和1)之间的随机数并乘以。如果任何一个结果是0,那么不管另一个结果是什么,整个结果都会变成0。唯一能得到1的方法是两个辊都是1。实际上,这可能不重要,但它会产生一个奇怪的图形。)


强制性的XKCD…return 4; // chosen by fair dice roll, guaranteed to be random.


用更离散的数字来考虑这一点可能会有所帮助。考虑到想要生成1到36之间的随机数,所以你决定最简单的方法是掷两个公平的6边骰子。你得到这个:

1
2
3
4
5
6
7
8
     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
  • 低:偏差:range - sqrt(rand(range^2))

有很多其他方法可以创建特定的偏差曲线。我对rand() * rand()做了一个快速测试,它得到了一个非常非线性的分布。


大多数rand()实现都有一些句点。也就是说,在大量调用之后,序列会重复。rand() * rand()的输出序列在一半时间内重复,因此从这个意义上说,它是"较少随机的"。

此外,如果不仔细构造,对随机值执行算术往往会导致较少的随机性。上面的一张海报引用了"rand()rand()rand()+(1)…………"(k次,比如说),这实际上倾向于k倍于rand()+收益范围的平均值。(这是一次随机行走,步幅对称。)

具体来说,假设rand()函数返回范围[0,1]内均匀分布的随机实数。(是的,这个例子允许无限的精度。这不会改变结果。)您没有选择特定的语言,不同的语言可能会做不同的事情,但是下面的分析对rand()的任何非反常实现进行了修改。产品rand() * rand()也在[0,1]范围内,但不再均匀分布。事实上,该乘积可能在区间[0,1/4]中,也可能在区间[1/4,1]中。更多的乘法将使结果进一步向零倾斜。这使得结果更加可预测。在广泛的笔画中,更容易预测==不那么随机。

在一致随机输入上,几乎所有的操作序列都是非一致随机的,从而提高了可预测性。小心点,你可以克服这一特性,但是在你真正想要的范围内生成一个均匀分布的随机数要比在算术上浪费时间容易得多。


"随机"和"更随机"有点像问哪个零更为零。

在这种情况下,rand是一个prng,所以不是完全随机的。(事实上,如果知道种子的话,是可以预测的)。再乘以另一个值,它就不会或多或少地是随机的。

真正的加密类型rng实际上是随机的。通过任何类型的函数运行值都不能给它增加更多的熵,很可能会去掉熵,使它不再随机。


你要寻找的概念是"熵",即字符串的无序程度。比特的根据"最大熵"的概念,这个概念最容易理解。

一个具有最大熵的位串的近似定义是,它不能精确地表示为较短的位串(即使用某种算法将较小的字符串展开回原始字符串)。

最大熵与随机性的关联源于如果你随机选择一个数字,你几乎肯定会选择一个数字。它的位串接近于最大熵,也就是说,它不能被压缩。这是我们对"随机"数特征的最好理解。

所以,如果你想从两个随机样本中得到一个随机数,它是随机,将两个位字符串连接在一起。实际上,你只是把样本塞进一个双长单词的上下半部分。

更实际的是,如果你发现自己背着一个蹩脚的兰德(),它可以有时有助于把几个样本放在一起——尽管,如果它真的是收支平衡的话。那个程序没用。


被接受的答案很可爱,但还有另一种方法来回答你的问题。Pachydermpuncher的答案已经采用了这种替代方法,我将把它扩展一点。

考虑信息理论最简单的方法是用最小的信息单位,一个比特。

在C标准库中,rand()返回一个0到RAND_MAX范围内的整数,这是一个根据平台不同而定义的限制。假设RAND_MAX恰好被定义为2^n - 1,其中n是一个整数(在微软的实现中,n是15)。然后我们会说,一个好的实现将返回n位信息。

假设rand()通过翻转硬币找到一位的值来构造随机数,然后重复直到它有一批15位。然后这些位是独立的(任何一个位的值不影响同一批中其他位具有一定值的可能性)。因此,独立考虑的每个位就像一个介于0和1之间的随机数,并且在该范围内"均匀分布"(可能是0和1)。

位的独立性确保了以批位表示的数字也将在其范围内均匀分布。这是显而易见的:如果有15位,允许的范围是0到2^15 - 1=32767。该范围内的每个数字都是唯一的位模式,例如:

1
010110101110010

如果比特是独立的,那么没有模式比任何其他模式更可能发生。所以范围内所有可能的数字都是同样可能的。相反,如果rand()产生均匀分布的整数,那么这些数字是由独立的位组成的。

因此,把rand()看作是一条生产钻头的生产线,它恰好以任意大小的批次提供钻头。如果你不喜欢这个尺寸,把批量分成几个单独的位,然后把它们按你喜欢的数量放回一起(尽管如果你需要一个不是2的幂的特定范围,你需要缩小你的数字,到目前为止最简单的方法是转换成浮动的订单int)。

回到你原来的建议,假设你想从15批转到30批,向rand()要第一个数字,稍微移动15位,然后再加上一个rand()。这是一种将两个对rand()的调用组合在一起的方法,而不会干扰均匀分布。它的工作原理很简单,因为放置信息位的位置之间没有重叠。

这与"拉伸"EDOCX1的范围(0)乘以常数非常不同。例如,如果你想把EDOCX1的范围扩大一倍(0),你可以乘以2,但现在你只能得到偶数,而不能得到奇数!这不完全是一个平稳的分布,可能是一个严重的问题,取决于应用程序,例如轮盘赌类游戏,假设允许奇数/偶数下注。(从位的角度考虑,你可以直观地避免这个错误,因为你会意识到乘两等于把位向左移动一个位置(更重要),然后用零填充空白。所以很明显,信息量是相同的——只是移动了一点。)

在浮点数应用程序中,不能消除数字范围中的这种差距,因为浮点数范围内在地具有根本无法表示的差距:在每两个可表示的浮点数之间的差距中存在无限数量的缺少实数。呃!所以不管怎样,我们只需要学会适应差距。

正如其他人所警告的,直觉在这方面是有风险的,特别是因为数学家们无法抗拒实数的诱惑,实数令人毛骨悚然地混淆了充满奇异的无穷大和明显的悖论的事物。

但至少如果你认为它是位的术语,你的直觉可能会让你更进一步。比特是非常容易的-即使计算机也能理解它们。


正如其他人所说,简单的简短回答是:不,它不是更随机的,但它确实改变了分布。好的。

假设你在玩骰子游戏。你有一些完全公平的随机骰子。如果在每个骰子之前,你先把两个骰子放在一个碗里,摇晃它,随机选择一个骰子,然后滚动那个骰子,那么骰子会"更随机"吗?显然,这不会有什么不同。如果两个骰子都给出随机数,那么随机选择两个骰子中的一个就没有什么区别。无论哪种方法,你都会得到一个1到6之间的随机数,在足够多的卷上均匀分布。好的。

我想在现实生活中,如果你怀疑骰子不公平的话,这样的程序可能会有用。比如说,如果骰子有点不平衡,那么一个骰子往往比1/6的时间给出1,而另一个骰子往往给出6,那么在两个骰子之间随机选择会掩盖偏差。(尽管在这种情况下,1和6仍然会超过2、3、4和5。嗯,我想这取决于不平衡的性质。)好的。

随机性有很多定义。随机序列的一个定义是,它是由随机过程产生的一系列数字。根据这个定义,如果我掷一个公平的骰子5次,得到数字2,4,3,2,5,这是一个随机序列。如果我再掷同一个骰子5次,得到1,1,1,1,1,1,1,那么这也是一个随机序列。好的。

一些海报指出,计算机上的随机函数不是真正随机的,而是伪随机的,如果你知道算法和种子,它们是完全可预测的。这是真的,但大部分时间都完全无关。如果我洗牌,然后一次翻开一副牌,这应该是一个随机序列。如果有人偷看卡片,结果将是完全可预测的,但根据随机性的大多数定义,这不会使它减少随机性。如果这个系列通过了随机性的统计测试,我偷看卡片的事实不会改变这个事实。在实践中,如果我们赌的是一大笔钱,你就有能力猜测下一张牌,那么你偷看这张牌的事实是高度相关的。如果我们使用这个系列来模拟访问我们网站的访问者的菜单选择,以测试系统的性能,那么您偷看的事实将没有任何区别。(只要您不修改程序以利用这些知识。)好的。

编辑好的。

我不认为我能把我对蒙蒂霍尔问题的反应变成评论,所以我会更新我的答案。好的。

对于那些没有阅读《伯利撒利亚链接》的人来说,它的要点是:一个游戏节目的参赛者可以选择三扇门。一个是有价值的奖品,另一个是毫无价值的。他选了一扇门。在揭示它是胜利者还是失败者之前,主人打开门3,表明它是失败者。然后,他给参赛者机会切换到第二扇门。选手是否应该这样做?好的。

答案,这冒犯了许多人的直觉,是他应该转换。他最初的选择是获胜者的概率是1/3,另一扇门是获胜者的概率是2/3。我最初的直觉是,和其他许多人一样,在转换过程中不会有任何收获,几率已经被改变为50:50。好的。

毕竟,假设有人在主人打开丢失的门后打开了电视。那个人会看到另外两扇紧闭的门。假设他知道比赛的性质,他会说每扇门有1/2的机会隐藏奖品。观众的赔率是1/2:1/2,而选手的赔率是1/3:2/3?好的。

我真的必须考虑这个问题才能使我的直觉成形。要处理它,请理解当我们讨论这样一个问题的概率时,我们的意思是,给定可用信息,您分配的概率。对于将奖品放在门后的船员来说,例如门1,奖品在门后的概率为100%,而在其他两个门中的任何一个门后的概率为零。好的。

船员的赔率不同于选手的赔率,因为他知道选手不知道什么,也就是说,他把奖品放在哪个门后面。同样,参赛者的胜算也不同于观众的胜算,因为他知道观众不知道的东西,即他最初选择的门。这并不无关紧要,因为主人选择打开哪个门并不是随机的。他不会打开选手选的门,也不会打开隐藏奖品的门。如果这是同一扇门,他就有两个选择。如果它们是不同的门,就只剩下一扇门了。好的。

那么,我们如何得出1/3和2/3呢?当参赛者最初选择一扇门时,他有1/3的机会选择获胜者。我觉得这很明显。这意味着有2/3的机会,其他门之一是赢家。如果东道主让他有机会在不提供任何额外信息的情况下进行转换,就不会有任何收获。同样,这应该是显而易见的。但有一种方法是说他有2/3的机会通过换人而获胜。但他有两个选择。所以每个人只有2/3除以2=1/3的机会成为赢家,这并不比他最初的选择更好。当然,我们已经知道了最终的结果,这只是用另一种方式来计算。好的。

但现在主持人透露,这两个选择中的一个不是赢家。所以,在他没选门的2/3机会中,他现在知道2个选择中的1个不是。另一个可能是,也可能不是。所以他不再有2/3除以2。他开着的门是零,关着的门是2/3。好的。好啊。


假设您有一个简单的硬币翻转问题,其中偶数被认为是头,奇数被认为是尾。逻辑实现是:

1
rand() mod 2

在足够大的分布中,偶数的数目应该等于奇数的数目。

现在考虑稍微调整一下:

1
rand() * rand() mod 2

如果其中一个结果是偶数,那么整个结果应该是偶数。考虑4种可能的结果(偶数*偶数=偶数,偶数*奇数=偶数,奇数*偶数=偶数,奇数*奇数=奇数)。现在,在一个足够大的分布中,答案应该是75%的时间。

如果我是你,我敢打赌。

这个评论实际上更多的是解释为什么你不应该基于你的方法实现一个定制的随机函数,而不是讨论随机性的数学性质。


当你对随机数的组合有疑问时,你可以利用你在统计理论中学到的经验。

在OP的情况下,他想知道x*x=x^2的结果是什么,其中x是一个沿均匀分布的随机变量[0,1]。我们将使用CDF技术,因为它只是一对一的映射。

因为x~均匀[0,1]它的cdf是:fx(x)=1我们需要转换y<-x^2,因此y=x^2求逆x(y):sqrt(y)=x,这给我们x作为y的函数。接下来,找到导数dx/d y: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,请在域中集成它:从0到1集成1/(2 sqrt(y)),实际上,它弹出为1。另外,请注意,所述函数的形状看起来像是不真实的发布。

至于x1之类的事情+xn,(其中xi~uniform[0,1])我们可以直接求助于中心极限定理,该定理适用于存在力矩的任何分布。这就是z检验实际存在的原因。

用于确定结果PDF的其他技术包括雅可比变换(这是CDF技术的通用版本)和MGF技术。

编辑:作为澄清,请注意,我所说的是结果转换的分布,而不是它的随机性。这实际上是单独讨论的。另外,我实际得到的是(rand())^2。对于rand()*rand(),它要复杂得多,在任何情况下都不会导致任何类型的均匀分布。


这并不十分明显,但rand()通常比rand()*rand()更随机。重要的是,对于大多数用途来说,这实际上并不十分重要。

但首先,它们产生不同的分布。这不是问题,如果这是你想要的,但它确实很重要。如果你需要一个特定的分布,那么忽略整个"更随机"的问题。那么,为什么rand()更随机?

为什么rand()更随机(假设它产生范围为〔0..1〕的浮点随机数,这是很常见的),其核心是当你将两个fp数与尾数中的大量信息相乘时,你会从尾数中得到一些信息丢失;在一个ieee双pr中没有足够的位。决定浮点用于保存从[0..1]中随机选择的两个IEEE双精度浮点中的所有信息,并且这些额外的信息将丢失。当然,这没什么关系,因为你(可能)不会使用这些信息,但损失是真实的。你生产的是哪一个发行版(也就是说,你使用哪一个操作来进行组合),这也不重要。这些随机数中的每一个都有(最多)52位随机信息——这就是一个ieee双精度数能容纳的量——如果将两个或多个随机信息组合成一个,那么最多只能包含52位随机信息。

大多数随机数的使用甚至不像在随机源中实际使用的那样随机。得到一个好的prng,不要担心太多。(善良的程度取决于你对它做了什么;你在做蒙特卡洛模拟或加密时必须小心,否则你可能会使用标准的prng,因为这通常要快得多。)


根据您的计算机体系结构,将数字相乘的结果将在较小的解决方案范围内。

如果计算机显示16位数字,则cx1〔0〕表示0.1234567890123。乘以第二个rand(),0.1234567890123,得到0.0152415如果你重复实验10^14次,你肯定会找到更少的解决方案。


浮动随机数通常基于一种算法,该算法产生一个介于零和某个范围之间的整数。因此,通过使用rand()*rand(),您实际上是在说int_rand()*int_rand()/rand_max^2-意味着您排除了任何质数/rand_max^2。

这显著改变了随机分布。

rand()在大多数系统上都是均匀分布的,很难预测种子是否正确。除非你有一个特别的理由对它进行数学运算(例如,把分布塑造成一条需要的曲线)。


这些分布大多是因为必须限制或规范化随机数。

我们将其规范化为所有正的,在一个范围内,甚至在指定变量类型的内存大小的约束内。

换句话说,因为我们必须将随机调用限制在0和x之间(x是变量的大小限制),所以我们将有一组介于0和x之间的"随机"数字。

现在,当你把随机数加到另一个随机数上时,和将在0到2x之间……这会使数值偏离边缘点(当你在一个大的区间内有两个随机数时,把两个小数字加在一起和两个大数字加在一起的概率非常小通用电气公司。

想想这样的情况,如果你有一个接近于零的数字,你加上另一个随机数,它肯定会变大,远离0(这对于大数字是正确的,而且它不太可能有两个大数字(接近X的数字)由随机函数返回两次。

现在,如果你用负数和正数(相等地跨越零轴)来设置随机方法,情况就不再是这样了。

比如说RandomReal({-x, x}, 50000, .01),你会得到一个负的偶数分布,一个正的,如果你把随机数加在一起,他们会保持他们的"随机性"。

现在我不确定负到正跨度的Random() * Random()会发生什么…这是一个有趣的图表…但我现在必须重新开始编写代码。-P


  • 没有比这更随意的了。它不是随机的,就是非随机的。随机意味着"难以预测"。这并不意味着不确定性。如果random()是随机的,那么random()和random()*random()都是随机的。就随机性而言,分布是无关的。如果出现不均匀分布,则意味着某些值比其他值更有可能发生;它们仍然是不可预测的。

  • 由于涉及到伪随机性,所以这些数字具有很强的确定性。然而,在概率模型和仿真中,伪随机性通常是足够的。众所周知,使伪随机数生成器变得复杂只会使分析变得困难。它不太可能改善随机性;它经常导致统计测试失败。

  • 随机数的期望特性是重要的:重复性和再现性,统计随机性,(通常)均匀分布,大周期是少数。

  • 关于随机数的变换:如有人所说,两个或多个均匀分布的和产生正态分布。这是加性中心极限定理。它适用于任何源分布,只要所有分布都是独立的和相同的。乘法中心极限定理表示两个或多个独立且按序分布的随机变量的乘积是对数正态的。其他人创建的图看起来是指数型的,但实际上是对数正态的。所以random()*random()是对数正态分布的(尽管它可能不是独立的,因为数字是从同一个流中提取的)。这在某些应用中可能是可取的。然而,通常最好生成一个随机数并将其转换为对数正态分布数。random()*random()可能很难分析。

  • 有关更多信息,请访问我的书www.performorama.org。这本书正在建设中,但相关资料在那里。注意章节号可能会随着时间的推移而改变。第8章(概率论)--第10章第8.3.1和8.3.3节(随机数)。


    实际上,当你想到它时,rand() * rand()rand()的随机性小。这就是原因。

    从本质上讲,奇数和偶数的数目是相同的。说0.04325是奇数,就像0.388是偶数,0.4是偶数,0.15是奇数,

    这就是说,rand()具有相等的机会成为偶数或奇数的小数。

    另一方面,rand() * rand()的概率叠加有点不同。让我们说:

    1
    2
    3
    double a = rand();
    double b = rand();
    double c = a * b;

    ab都有50%的概率是偶数或奇数。知道那

    • 偶数*偶数=偶数
    • 偶数*奇数=偶数
    • 奇数*奇数=奇数
    • 奇数*偶数=偶数

    也就是说,有75%的几率c是偶数,而只有25%的几率是奇数,这使得rand() * rand()的值比rand()更容易预测,因此随机性更小。


    我们可以使用Kolmogorov复杂性如果数列不能被压缩,那么它是我们在这个长度上能达到的最随机的…我知道这种测量方法更像是一种理论上的选择…


    使用线性反馈移位寄存器(LFSR)实现原始多项式。

    结果将是一个2^n伪随机数的序列,即没有重复的序列,其中n是LFSR中的位数……使分布均匀。

    http://en.wikipedia.org/wiki/linear_feedback_shift_寄存器http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf

    使用一个基于计算机时钟的microsecs的"随机"种子,或者在文件系统中一些不断变化的数据上使用MD5结果的一个子集。

    例如,一个32位的LFSR将从一个给定的种子开始,按顺序生成2^32个唯一的数字(没有2个相似的数字)。序列将始终保持相同的顺序,但对于不同的种子,起始点将不同(显然)。所以,如果种子之间可能的重复序列不是问题,这可能是一个好的选择。

    我使用128位LFSR在硬件模拟器中使用种子生成随机测试,这是MD5对不断变化的系统数据的结果。


    假设rand()返回[0, 1)之间的一个数字,很明显rand() * rand()将偏向于0。这是因为将x乘以[0, 1)之间的一个数字将导致一个小于x的数字。下面是10000多个随机数的分布:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    google.charts.load("current", { packages: ["corechart"] });
    google.charts.setOnLoadCallback(drawChart);

    function drawChart() {
      var i;
      var randomNumbers = [];
      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("number","Value");
      randomNumbers.forEach(function(randomNumber) {
        data.addRow([randomNumber]);
      });
      chart.draw(data, {
        title: randomNumbers.length +" rand() * rand() values between [0, 1)",
        legend: { position:"none" }
      });
    }
    1
    2
    3
    <script src="https://www.gstatic.com/charts/loader.js">

    Generating chart...

    如果rand()返回一个介于[x, y]之间的整数,那么您将得到以下分布。注意奇数和偶数的数目:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    google.charts.load("current", { packages: ["corechart"] });
    google.charts.setOnLoadCallback(drawChart);
    document.querySelector("#draw-chart").addEventListener("click", drawChart);

    function 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) {
        return;
      }
      var i;
      var randomNumbers = [];
      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("number","Value");
      randomNumbers.forEach(function(randomNumber) {
        data.addRow([randomNumber]);
      });
      chart.draw(data, {
        title: randomNumbers.length +" rand() * rand() values between [" + min +"," + max +"]",
        legend: { position:"none" },
        histogram: { bucketSize: 1 }
      });
    }
    1
    2
    3
    4
    5
    6
    7
    <script src="https://www.gstatic.com/charts/loader.js">

    <input type="number" id="rand-min" value="0" min="0" max="10">
    <input type="number" id="rand-max" value="9" min="0" max="10">
    <input type="button" id="draw-chart" value="Apply">

    Generating chart...


    很容易证明这两个随机数的和不一定是随机的。想象一下你有一个6边的模具和辊。每个数字出现的几率为1/6。现在假设你有两个骰子,并把结果相加。这些总数的分布不是1/12。为什么?因为某些数字比其他数字多。它们有多个分区。例如,数字2是1+1的和,但7可以由3+4或4+3或5+2等构成。所以它有更大的机会出现。

    因此,在这种情况下,在随机函数上加上一个变换并不能使其更随机,也不一定保持随机性。在上面的骰子的情况下,分布偏向7,因此随机性较小。


    好的,我将尝试添加一些值来补充其他答案,方法是说您正在创建并使用随机数生成器。

    随机数生成器是一种具有多个特性的设备(在非常一般的意义上),可以对其进行修改以适应某个目的。其中一些(来自我)是:

    • 熵:与香农熵一样
    • 分布:统计分布(泊松、正态等)
    • 类型:数字的来源(算法、自然事件、组合等)和应用的算法。
    • 效率:执行的速度或复杂性。
    • 模式:周期性、顺序、运行等。
    • 可能更多…

    在这里的大多数答案中,分布是主要关注点,但是通过混合和匹配函数和参数,您可以创建生成随机数的新方法,这些随机数将具有不同的特性,其中一些特性的评估乍一看可能并不明显。


    正如其他人已经指出的那样,这个问题很难回答,因为我们每个人都有他自己的头脑中的随机性。

    这就是为什么,我强烈建议您花些时间阅读本网站,以便更好地了解随机性:

    • 网址:http://www.random.org/

    回到真正的问题上来。在这个术语中,没有多少随机性:

    两者都只是随机出现的!

    在这两种情况下-仅rand()或rand()*rand()-情况相同:几十亿个数字之后,序列将重复(!).对于观察者来说,这似乎是随机的,因为他不知道整个序列,但是计算机没有真正的随机源——所以他也不能产生随机性。

    例如:天气是随机的吗?我们没有足够的传感器或知识来确定天气是否随机。


    答案将取决于,希望rand()*rand()比rand()更随机,但如下所示:

    • 两个答案都取决于你的值的位大小。
    • 在大多数情况下,您的生成依赖于伪随机算法(它主要是一个数字生成器,取决于您的计算机时钟,而不是那么随机)。
    • 让你的代码更易读(不要用这种咒语随意调用巫毒神)。

    好吧,如果你检查上面的任何一个,我建议你使用简单的"rand()"。因为你的代码更易于阅读(不会问你自己为什么要写这个,因为…嗯…超过2秒),易于维护(如果您想用超级兰特替换您的兰德函数)。

    如果你想要一个更好的随机的,我建议你从任何能提供足够噪声(无线电静态)的来源传输它,然后一个简单的rand()就足够了。