【问题标题】:Why this randomization method gives skewed results?为什么这种随机化方法会产生偏斜的结果?
【发布时间】:2014-02-28 18:55:52
【问题描述】:

我使用了两种不同的随机化方法,一种给出的结果的方差符合我的预期,另一种方法给出的结果也有偏差,而且也非常一致。

方法:

function randomA() {
    var raw = Number((Math.random()+'').substr(2));
    return raw % NUM_OF_POSSIBLES;
}

function randomB() {
    var raw = Math.round(Math.random()*10000);
    return raw % NUM_OF_POSSIBLES;
}

NUM_OF_POSSIBLES = 2 第一种方法 (randomA()) 产生相当一致的零 (64%) 和 36% 的 1。而radnomB() 几乎是 50/50。 如果NUM_OF_POSSIBLES = 5 再次以非常一致的方式倾斜第一种方法: 0: 10%, 1: 23%, 2: 22%, 3: 22%, 4: 23%,而第二个给每个结果大约 20%。

您可以在此处找到包含多个测试的完整代码:jsfiddle

为什么第一种方法偏斜,为什么偏斜一致?

【问题讨论】:

  • 有些事情让我觉得这是因为你在模数之前增加了数字的大小,但对于我的生活,我想不出为什么。这可能与Number() 格式化输出的方式有关。尽管。如果没有*10000,两者之间是否一致?
  • @Askanison4 我希望我能同意(或反驳!)但我自己也很困惑,办公室里的人对此有点发疯:D
  • @Askanison4 如果我不乘我不能模,但如果我只乘以 100 结果保持不变。

标签: javascript random


【解决方案1】:

您会得到偏差,因为 Math.random() 的结果并不总是相同的长度,因此例如 0.1230.1235 计入“ones”堆。

你可能认为如果你用尾随零来平衡长度,它会被纠正,但这也不正确,因为0.123 可能是一个四舍五入的0.122999999999

第一种方法的真正错误是依赖于不精确分数的最低有效位(%2 和 %5 都只受最后一位影响),当从二进制转换为十进制以进行表示时,会出现舍入错误.

分数的原始二进制形式可能是均匀分布的,但无法在 Javascript 中读取。

现在,如果有人能解释四舍五入的小数部分的尾随数字的分布......

【讨论】:

    【解决方案2】:

    我发现 randomA 以这种方式工作的原因是因为 java 脚本使用 floating poing numbers 和 52+1 位(基本格式章节下的表格)。所以随机函数返回过大的值后会被四舍五入,例如

    Math.pow(2, 54) +1 
    //18014398509481984
    Math.pow(2, 54)  
    //18014398509481984
    Math.pow(2, 54)  -1
    //18014398509481984
    

    全部返回相同的值,除以 2(因为四舍五入)。

    为了进一步了解,您可以播放并查看二进制格式的外观,示例:

    parseInt(Math.pow(2, 54) - 2).toString(2)
    //"111111111111111111111111111111111111111111111111111110"
    parseInt(Math.pow(2, 54) - 3).toString(2)
    //"111111111111111111111111111111111111111111111111111100"
    parseInt(Math.pow(2, 54) ).toString(2)
    //"1000000000000000000000000000000000000000000000000000000"
    parseInt(Math.pow(2, 54) -1).toString(2)
    //"1000000000000000000000000000000000000000000000000000000"
    

    【讨论】:

      【解决方案3】:

      我不完全确定,但我的猜测是它与 JavaScript 将数字格式化为字符串时使用的舍入模式有关。在第一种情况下,您的结果取决于最后一位数字的选择,这对四舍五入很敏感。如果它偏向偶数,那将解释您的结果。 (在NUM_OF_POSSIBLES == 5 的情况下,这是因为最后一位数字不足 5s。)在第二个例程中,结果取决于字符串表示的中间数字,这几乎与该影响隔离。

      在第一个例程中去掉最后一两个数字可能会得到更好的结果。

      编辑我刚刚通过实验确认如果将第一个例程更改为砍掉最后一个数字:

      function randomA() {
          var raw = String(Math.random());
          raw = raw.substring(2, raw.length-1);
          return raw % NUM_OF_POSSIBLES;
      }
      

      那么当NUM_OF_POSSIBLES == 25 时,偏见似乎消失了。

      【讨论】:

      • Javascript 实际上偏向偶数。 MDN Math.random(): "JavaScript 中的数字是 IEEE 754 浮点数,具有舍入到最近偶数行为"
      • 是的,必须与舍入有关
      • 在第一种方法中去掉最后一个数字效果很好,但我不确定这如何解释结果的一致性 - 使用任意数量的 NUM_OF_POSSIBLES
      • @MeLight - 偏差解释了 2 和 5 的结果。我没有看到 NUM_OF_POSSIBLES 的许多其他值(例如 3 或 7)存在偏差。我怀疑 NUM_OF_POSSIBLES 的因子为 2 或 5 会显示出对 randomA 的偏差,因为 JavaScript 生成表示的最后一位数字的方式存在偏差。
      猜你喜欢
      • 1970-01-01
      • 2013-02-19
      • 1970-01-01
      • 2023-04-11
      • 2015-06-10
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多