关于JavaScript中的随机数方法

最近在琢磨内置对象Math的时候,参考了很多网上资料,不过我在Google中搜索js 随机整数,出来很多博客文章,很遗憾,在我看来排名靠前的这些文章都是错误的。接下来我将会论证我这一观点,同时把我所理解的Math.random()方法跟你分享。
图片描述

获取端点问题;

先看这一篇,Javascript实现随机整数

在这篇文章中,作者给出了如下方法,根据他的文章描述,这个算法能产生startend之间的随机整数。

javascriptfunction rnd(start, end){
    return Math.floor(Math.random() * (end - start) + start);
}
一个需要确认的问题

在说我的观点之前,我希望先明确一件事情,设想别人跟你提了一个需求:

需要一个生成ab之间随机整数的方法。

这时候我觉得你至少需要跟对方确认一个问题:包不包括两个端点,即ab ?
(其实还有一些问题需要考虑的,比如传入的ab如果不是数字类型?如果是小数?如果是负数?如果ab大?为了专注本文要讨论的内容,我们假定传入的ab都是合法的正整数,且a<b。)

如果对方给你确认了,那是坠吼的;但是如果对方没有确认,如何理解这一需求?我认为在对上述需求没有更多说明的情况下,以下两个是靠谱的理解:

  1. 既要包括端点a,也要包括端点b
  2. 既不包括端点a,也不包括端点b

所以,如果你实现的方法能获取的只包含其中一个端点,我觉得这种实现是不太理想的,你再琢磨这句话:ab之间的随机整数

如果你也认同我的这段论述,接下来回到开头那个方法,看他能不能实现获取从startend之间的随机整数;方法主体就一个运算表达式:

javascriptreturn Math.floor(Math.random() * (end - start) + start);

逐步分析:

javascriptMath.random();                               //[0,1)
Math.random()*(end-start);                   //[0,end-start);
Math.random()*(end-start)+start;             //[start,end);
Math.floor(Math.random()*(end-start)+start); //{ x | x>=start,x<end,x∈N}

第一行,Math.random()方法返回的是01之间的浮点数,注意,__包括0,不包括1!__ECMA语言标准里明确规定了:

Returns a Number value with positive sign, greater than or equal to 0 but less than 1

所以,这篇博客,和这篇博客是不正确的;由于这两篇占据结果第一页的博文比较古老,我甚至在想是不是ECMA标准一开始不是这样子的,然后查了一下,ECMA标准从第一个版本对random方法的规定就是现在这个样子。

第二行,Math.random()*(end-start);则返回0end-start之间的浮点数,包含0,不包含end-start

第三行, Math.random()*(end-start)+start;返回startend之间的浮点数,包含start,不包含end

第四行,Math.floor(Math.random()*(end-start)+start);。这是最关键的一行,对上一行产生的浮点数进行向下取整,既然是向下取整,结果可能取到start,却永远取不到end

根据前述理解,这样的实现我认为是不合要求的。所以,这篇文章也是不正确的。
另外,这几篇几个不错的JavaScript随机...js生成随机数采用parseInt对获取的浮点数进行取整操作,也是同样的问题,能取到左端点,却无法取到右端点。parseInt操作浮点数的效果相当于Math.floor()

勘误:

之前写的上面这句话“parseInt操作浮点数的效果相当于Math.floor()”,我在看了这篇文章之后发现这句话是不对的,抱歉。但我的结论是不变的:Math.random()的结果范围包括0,因此parseInt(Math.random())也可能取到0

而这一篇JavaScript random方法得到随机整数,采用的是Math.ceil()方法进行向上取整,

javascriptMath.ceil(Math.random()*3);//得到1-3的整数

这样确实既能取到右端点,也能取到左端点,但是作者的左端点标错了,这个是有可能能取到0的,尽管取到0的概率是无限趋近于0;

这样引伸出另一个问题:取得的随机整数范围里,各整数出现的概率是否一致?

获取概率问题

一个概率不均等的方法

在之前有位老师给出的获取随机数方法是下面这样(要求了必须包括端点);

javascriptfunction getRandom(n,m){
  //省略特殊情形下的处理过程,比如n>m,或者n、m之一无法转化为有效数字;
  return Math.round(Math.random()*(m-n)+n);
}

一个获取随机整数的方法,如果不格外的声明,我觉得有一个默认的条件应该是:

生成每个整数的概率应当是均等的;

根据第一部分的分析,这个方法能获取的浮点数的范围是nm之间,包括n,不包括m;而这个方法中取整是采用Math.round()四舍五入;这样的话:

  1. 当取出的结果x∈[n,n+0.5)时,会四舍五入为n;区间范围为0.5,概率为0.5/(m-n)*100%;
  2. 当取出的结果x∈[n+0.5,n+1.5)时,会四舍五入为n+1;区间范围为1,概率为1/(m-n)*100%;
  3. 当取出的结果x∈[n+1.5,n+2.5)时,会四舍五入为n+2;区间范围为1,概率为1/(m-n)*100%;
  4. ......
  5. 当取出的结果x∈[m-0.5,m)时,会四舍五入为m;区间范围为0.5,概率为0.5/(m-n)*100%;

通过以上分析,该算法确实可以达到目标,取到nm之间的随机整数,但是并不是每个整数出现的概率都是相等的,具体来说,取得两边端点的整数概率是其他数字的一半。所以,我认为这也是不够完美的。

这样的话,在写一个获得概率均等的随机整数方法的时候,相信你知道应该注意些什么问题了吧。

总结

总结一下,当我们在获取随机整数的时候,有两个问题需要特别注意:

  1. 一定要仔细检查两边端点是否是否能取到?是否与需求一致?
  2. 获取到的每个整数的概率是否均等?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值