大家都知道Math.random是 javascript 中返回偽隨機數的函數,但查看 MDN,
The Math.random()
function returns a floating-point, pseudo-random number in the range [0, 1)
that is, from 0 (inclusive) up to but not including 1 (exclusive)
Returns a Number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy.
以上都是認為能夠取到0,
但是在js權威書籍 Professional javascript for web developers 3rd edition 中,描述如下:
The Math.random() method returns a random number between the 0 and the 1, not including either 0, or 1.
明確指出不包括 0, 或 1,
到底怎么回事呢,那么我們來做一個實驗:
var count=0; for(var i=0;i<100000000;i++){ if(Math.random()===0.0){ count++; } } console.log("count:"+count);
我們循環產生1億個隨機數,看能否得到0.0, 結果輸出“count:0”,即不會得到0.0,
我們再來看能否得到1.0,
var count=0; for(var i=0;i<100000000;i++){ if(Math.random()===1.0){ count++; } } console.log("count:"+count);
結果輸出“count:0”,即沒有得到1.0,
接着我們把循環增加到10億,結果是沒有得到0.0,也沒有得到1.0
把循環增加到100億,結果是得到1次0.0, 但沒有得到1.0
但實際上使用上,我們幾乎不太可能去產生100億個隨機數,也不會取判斷單獨取0.0的概率,因此,從理論上說,Math.random()產生 [0,1)區間的數,但實際使用上能否取到0.0對我們的實用意義不大,可以看成是(0,1)開區間。
第一:因為對一個連續型隨機變量來說,取具體一個點的概率是0,
第二:我們使用Math.random()時我們大多數應用無非是產生一個數字,或者是產生一組數字,
當需要產生一個數字時候,我們是不需要利用 “這個數字的出現概率” 這一信息的,僅使用這個數字而已。
當需要產生一組數字的時候,這時需要用到:“這個數字的出現概率”,這實際是要計算累積概率密度,我們知道在計算連續型隨機變量落在某一個區間內的概率時是不需要區分該區間是開區間,閉區間或者是半閉區間,也就是說,取0.0或者不取0.0不影響我們結果。
例如,我們希望以相等的概率隨機出現0,或者1,我們實際上可以通過計算落在(0, 0.5),(0.5, 1)這兩個區間內的累積概率分別代表0,和1,當然這里的區間也可以是閉區間[0, 0.5] ... 所以取不取0.0對我們的結果沒有影響。
因此,當我們需要獲得指定區間的隨機數時,我們可以在 Math.random()上乘以一定的數值,把整個區間范圍拉長放大,
例如,我們需要返回 [1,10] (注意是閉區間,包括1和10),我們可以用 Math.floor(Math.random()*10+1),獲得,
這里使用 floor 函數向下取整,而不能使用 round 函數四舍五入取整,round 取整后得到的是非均勻分布。
因為我們要每個數字出現的概率相等,就要保證每個區間長度相等,使用 round 取整后, 映射到1的區間為(1,1.5) 映射到2的區間為(1.5, 2.5)...... (9.5,10.5),(10.5,11) 可見其區間長度是不同的,即1和11出現的概率為其他數字出現概率的一半。
實驗代碼:
var temp; var arr=[0,0,0,0,0,0,0,0,0,0]; for(var i=0;i<1000000000;i++){ temp=Math.floor(Math.random()*10+1); arr[temp]=arr[temp]+1; } for (var j = 0; j < arr.length; j++) { console.log(j + ":" + arr[j]); }
結果為:
得到1的概率:0.099990183 得到2的概率:0.100023429 得到3的概率:0.100037064 得到4的概率:0.099983931 得到5的概率:0.100004498 得到6的概率:0.09999009 得到7的概率:0.099987366 得到8的概率:0.100001322 得到9的概率:0.099990864 得到10的概率:0.099991253
可以看到出現各個值的概率是基本相等的。
如果是使用 round,
var temp; var arr=[0,0,0,0,0,0,0,0,0,0,0,0]; for(var i=0;i<1000000000;i++){ temp=Math.round(Math.random()*10+1); arr[temp]=arr[temp]+1; } for (var j = 0; j < arr.length; j++) { console.log("得到"+j+"的概率:" + arr[j]/1000000000); }
得到:
得到1的概率:0.049978171 得到2的概率:0.100013093 得到3的概率:0.10004957 得到4的概率:0.099999108 得到5的概率:0.099998023 得到6的概率:0.099991361 得到7的概率:0.10000203 得到8的概率:0.09999017 得到9的概率:0.099980942 得到10的概率:0.100001593 得到11的概率:0.049995939
得到1和11的概率為其他數字的一半。
所以,Math.random 服從 [0,1) 區間的均勻分布,因為均勻分布是連續性分布,我們也可以說是 服從 (0,1)區間的均勻分布,這不影響我們使用累計概率密度。
因此,如果想獲得 [min, max], 可以使用 Math.floor(Math.random() * (max - min + 1)) + min;
如果想獲得 [min, max), 可以使用 Math.floor(Math.random() * (max - min )) + min;
如果想獲得 (min, max], 可以使用 Math.ceil(Math.random() * (max - min )) + min;
我們再看一個應用,是 百度 2014年秋校園招聘 中,web前端開發崗位 的一道題,要求生成隨機顏色,實現代碼如下:
function randomColor(){ var rc=function(){ return Math.floor(Math.random()*256); } return "rgb("+rc()+","+rc()+","+rc()+")"; }
注意,rgb顏色區間為[0,255], 0和255是能夠取到的。
再繼續,如何產生服從正態分布的隨機數呢?
請見下篇: