今天要聊一个学编程以来很感兴趣的话题:计算机的”随机“是真正的随机码?
暂时将这个大问题放下,先来解决一个问题:数组乱序
这很简单啊,例如在网上广为流传的代码
function shuffle(arr) {
return arr.sort(function() {
return Math.random() - 0.5;
});
}
https://75team.com/post/array-shuffle.html
直到我看这篇文章时都认为上述算法很巧妙。作者的测试代码
var arr = [0,1,2,3,4,5,6,7,8,9];
var res = [0,0,0,0,0,0,0,0,0,0];
var t = 10000;
for(var i = 0; i < t; i++){
var sorted = shuffle(arr.slice(0));
sorted.forEach(function(o,i){
res[i] += o;
});
}
res = res.map(function(o){
return o / t;
});
若算法是随机乱序的,则10000次测试后,每个位置出现的不同数字次数应该很接近,所以把每项的数字求和再除以10000,结果应该接近数组的平均值4.5。但可惜,结果不是4.5。我的结果是
[ 1.5845,
1.5982,
2.2414,
3.0622,
3.9838,
4.899,
5.7319,
6.582,
7.3192,
7.9978 ]
请仔细阅读文章,文章很详细的解释为何出现这样的现象,在最后作者的数学归纳法证明经典洗牌算法能实现真正的数组乱序,简直天秀。
在JavaScript中,随机数是由Math.random()提供,但这是伪随机数。伪随机数的意思就是字面意思,不是真实不可预测的随机,而是按照一定的模拟算法产生的随机,按照这套算法产生的结果是确定的,称为伪随机。
也可以说是 伪随机性(英语:Pseudorandomness)是一个过程似乎是随机的,但实际上并不是。伪随机数是看似随机实质是固定的周期性序列,也就是有规则的随机。
随机数概念:
随机性:不存在统计学偏差,是完全杂乱的数列
不可预测性:不能从过去的数列推测出下一个出现的数
不可重现性:除非将数列本身保存下来,否则不能重现相同的数列
关于随机数的更多概念请阅读这篇文章:https://juejin.im/post/5b95004ee51d450e615fd904
总结如下:任何确定的算法都只能实现伪随机,不能实现真随机。
有限状态机不能产生真正的随机数的,所以,现代计算机中,无法通过一个纯算法来生成真正的随机数,无论是哪种语言,单纯的算法生成的数字都是伪随机数,都是由可确定的函数通过一个种子,产生的伪随机数。
所以,真随机是无法单纯由数学算法求得,必须由物理现象得到(这符合我一直以来的想法和直觉)。
延伸阅读
https://github.com/webproblem/Blog/issues/7
https://github.com/abbshr/abbshr.github.io/issues/46
题外话
后面的话题好像偏题了…未来打算学习设计模式,https://github.com/nefe/You-Dont-Need-jQuery 这个仓库或者是 30 seconds of code。学JavaScript以来很少使用jQuery这个曾经很火的库,因为ES6很多地方都学习jQuery的优点,而且前端三大框架现在太火了。但对于这个如此成熟高效的库值得每个学习前端去研究的。希望能弥补我知识的短板吧。