正文

错误示范

我的错误写法:

    Math.ceil(Math.random()*8+2)  

解析:
产生该错误的原因是没有用区间思考时候没有考虑ceil函数的具体机制,直接使用函数造成的:
误认为以上代码等同于:

    Math.ceil([0,1)*(n-m)+m)
    //进一步对左开右闭区间处理如下:
    Math.ceil([m,n))
    // 于是取到m到n的任意整数,因为Math.ceil(0) == 0

实际上,Math.random() 能使Math.ceil取到0的是Math.random为0时,单点在区间中出现概率为0,因此测试结果表明无法取到左边界

网上错误方案

方案一

    Math.round(Math.random()*8+2) 

方案二

    parseInt(Math.random()*8+2)

解析:
初看起来,似乎方案一完美实现了取到闭区间内所有整数,实际上:

    [2,2.5)  => 取2
    [2.5,3.5) => 取3
    ...
    [9.5,10) => 取10

注意看,取到2和10时的两个区间长度是取到其他数字区间长度的一半,意味着生成随机数的概率分布不均匀!


对于方案二,错误在于parseInt是用于解析字符串的函数:

    parseInt(string, radix);

将其用于解析数字在规范中并未说明,但测试表明,当0.0000007类型的数字(超过6位的小数)会自动转换为7e-7的科学计数法,这样parseInt会解析为7,与我们本意解析为0不同,产生意外的结果

合理方案

    Math.floor(Math.random()*9+2)
    // 也就是区间长度加1与随机数相乘
    Math.floor(Math.random()*(m-n+1)+n)

解析:
这样操作使得分布均匀且不产生以外数字:

    [2,3) => 取2
    [3,4) => 取3
    ...
    [10,11) =>取10

总结

  • 常用产生闭区间内整数的方法是Math.floor
  • parseInt应该只用于处理字符串的数字解析

参考

parseInt函数
segmentfault上我自己的提问
parseInt只应解析字符串