繁体   English   中英

Math.random() 不满意

[英]Math.random() unsatisfactory

让我们成为一个包含从 A 到 Z 的 26 个字母的列表。我们将列表与 Fisher-Yates 算法混合(参见https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle )。 我们对表格的第一个字母感兴趣:

  • 理论上,每个字母出现在第一个 position 的概率相同:1/26 ~ 3.85%。
  • 实际上,情况并非如此,如下面的分布所示。 找到 B 的概率为 5.14%,而 Z 的概率为 2.89%。B 出现在第一个 position 中的机会比 Z 多 1.78 倍(几乎是 2 倍,这是巨大的)

分配

这是我使用的代码:

"use strict";

// mix
const mix = array => {
    const { length: n } = array;
    for (let i = 0; i < n; i++) {
        const x = Math.floor(Math.random() * n);
        [array[i], array[x]] = [array[x], array[i]];
    }
    return array;
};

const A = 'A'.charCodeAt(0);
const NB_LETTERS = 26;

const TABLE = {};
for (let i = 0; i < NB_LETTERS; i++) TABLE[String.fromCharCode(A + i)] = 0;

for (let N = 1; ; N++) {

    // init
    const array = [];
    for (let i = 0; i < NB_LETTERS; i++) array[i] = String.fromCharCode(A + i);

    mix(array);

    TABLE[array[0]]++;

    if (N % 1000000 === 0) {
        console.log('');
        console.log("N =", N);
        console.log(
            Object.entries(TABLE)
                .map(([letter, n]) => {
                    const freq = n / N;
                    return letter + '\t' + freq.toString().replace('.', ',');
                })
                .join('\n')
        );
    }
}

问题:

  • 你得到相同的结果吗?
  • 它来自Math.random()吗? 我想是的...您知道可以提供均匀分布的替代方案吗?

提前致谢

function mix中的 shuffle 算法未正确实现。

引用的 Wikipedia 文章中的算法规定,在每次迭代中取随机数的范围应该不同,这在您的实现中并非如此,因此是非均匀分布。

进行此更正:

    const x = i + Math.floor(Math.random() * (n - i));

其他实现(有一些优化)可以在如何随机化(随机播放)JavaScript 阵列中找到?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM