最近在琢磨内置对象Math
的时候,参考了不少网上资料,不过我在Google中搜索js 随机整数
,出来不少博客文章,很遗憾,在我看来排名靠前的这些文章都是错误的。接下来我将会论证我这一观点,同时把我所理解的Math.random()
方法跟你分享。javascript
在这篇文章中,做者给出了以下方法,根据他的文章描述,这个算法能产生start
到end
之间的随机整数。php
javascriptfunction rnd(start, end){ return Math.floor(Math.random() * (end - start) + start); }
在说个人观点以前,我但愿先明确一件事情,设想别人跟你提了一个需求:html
须要一个生成
a
到b
之间随机整数的方法。java
这时候我以为你至少须要跟对方确认一个问题:包不包括两个端点,即a
和b
?
(其实还有一些问题须要考虑的,好比传入的a
和b
若是不是数字类型?若是是小数?若是是负数?若是a
比b
大?为了专一本文要讨论的内容,咱们假定传入的a
和b
都是合法的正整数,且a
<b
。)算法
若是对方给你确认了,那是坠吼的;可是若是对方没有确认,如何理解这一需求?我认为在对上述需求没有更多说明的状况下,如下两个是靠谱的理解:segmentfault
- 既要包括端点
a
,也要包括端点b
。- 既不包括端点
a
,也不包括端点b
。
因此,若是你实现的方法能获取的只包含其中一个端点,我以为这种实现是不太理想的,你再琢磨这句话:a
到b
之间的随机整数。app
若是你也认同个人这段论述,接下来回到开头那个方法,看他能不能实现获取从start
到end
之间的随机整数;方法主体就一个运算表达式:less
javascriptreturn Math.floor(Math.random() * (end - start) + start);
逐步分析:dom
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()
方法返回的是0
到1
之间的浮点数,注意,__包括0
,不包括1
!__ECMA语言标准里明确规定了:spa
Returns a Number value with positive sign, greater than or equal to 0 but less than 1
因此,这篇博客,和这篇博客是不正确的;因为这两篇占据结果第一页的博文比较古老,我甚至在想是否是ECMA标准一开始不是这样子的,而后查了一下,ECMA标准从第一个版本对random
方法的规定就是如今这个样子。
第二行,Math.random()*(end-start);
则返回0
到end-start
之间的浮点数,包含0
,不包含end-start
。
第三行, Math.random()*(end-start)+start;
返回start
到end
之间的浮点数,包含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); }
一个获取随机整数的方法,若是不格外的声明,我以为有一个默认的条件应该是:
生成每一个整数的几率应当是均等的;
根据第一部分的分析,这个方法能获取的浮点数的范围是n
到m
之间,包括n
,不包括m
;而这个方法中取整是采用Math.round()
四舍五入;这样的话:
- 当取出的结果
x∈[n,n+0.5)
时,会四舍五入为n;区间范围为0.5,几率为0.5/(m-n)*100%;- 当取出的结果
x∈[n+0.5,n+1.5)
时,会四舍五入为n+1;区间范围为1,几率为1/(m-n)*100%;- 当取出的结果
x∈[n+1.5,n+2.5)
时,会四舍五入为n+2;区间范围为1,几率为1/(m-n)*100%;- ......
- 当取出的结果
x∈[m-0.5,m)
时,会四舍五入为m;区间范围为0.5,几率为0.5/(m-n)*100%;
经过以上分析,该算法确实能够达到目标,取到n
到m
之间的随机整数,可是并非每一个整数出现的几率都是相等的,具体来讲,取得两边端点的整数几率是其余数字的一半。因此,我认为这也是不够完美的。
这样的话,在写一个得到几率均等的随机整数方法的时候,相信你知道应该注意些什么问题了吧。
总结一下,当咱们在获取随机整数的时候,有两个问题须要特别注意:
- 必定要仔细检查两边端点是不是否能取到?是否与需求一致?
- 获取到的每一个整数的几率是否均等?