1. 程式人生 > >js 為何範圍內隨機取整要用floor,而不是ceil或者round呢

js 為何範圍內隨機取整要用floor,而不是ceil或者round呢

 壹 ❀ 引

我在如何使用js取任意範圍內隨機整數這篇部落格中,列舉並分析了取[n,m)與[n,m]範圍內整數的通用方法,並在文章結果留了一個疑問;為什麼通用方法中取整操作,我們使用Math.floor()而不是Math.ceil()或者Math.round()方法呢?

知其然更知其所以然,加上在GitHub中那道筆試題答案下,不少網友的答案使用了round或ceil方法來取整,說明不少人對於隨機取整為何一定要用floor方法是沒有一個深刻理解的,那麼本文就對於這個問題展開分析。

 貳 ❀ round ceil floor有何區別

在弄懂這個問題前,我們先將這三個方法的區別說清楚,它們都是JavaScript提供的數字取整方法,但卻有著本質區別。

1.關於Math.round()

Math.round()的含義是將一個數字四捨五入為最接近的整數,四捨五入大家不會陌生,一個數字如果是4那就捨棄掉,如果是5,那就進一。

Math.round(0.5); //1
Math.round(1.2); //1
Math.round(2.41); //2
Math.round(-3.55); //-4

2.關於Math.ceil()

Math.ceil()的含義是向上取整,說直白點,就是得到一個大於等於且最接近自己的整數,不難理解。

Math.ceil(0); //0
Math.ceil(1.2); //2
Math.ceil(2.41); //3
Math.ceil(-3.55); //-3

3.關於Math.floor()

Math.floor()剛好與Math.ceil()相反,這是一對冤家,它表示的是向下取整,也就是找小於等於且最接近自己的整數。

Math.floor(0); //0
Math.floor(1.2); //1
Math.floor(2.41); //2
Math.floor(-3.55); //-4

 叄 ❀ 隨機整數概率問題

1.使用round的問題

我們知道,當取[0,5]範圍內隨機整數時,從概率角度,我們是希望每個隨機數出現概率是相同的,那麼當我們使用round方法會有什麼問題呢?

round的作用是四捨五入取整,為了不那麼複雜,我們將數字範圍劃分為0 -- 0.5 -- 1 -- 1.5 -- 2 -- 2.5 -- 3 -- 3.5 -- 4 -- 4.5 -- 5 這幾個階段。

很明顯,當範圍是0 -- 0.499之前被四捨五入為0,而0.5 -- 1與1 -- 1.4999可四捨五入為1,同理,2階段,3階段,4階段都是前後兩個範圍,4.5 -- 5可四捨五入為5。

由此可以統計出2,3,4出現的概率要整整比0,5兩個邊界數字出現的概率高百分之50,我們做個簡單的測試:

Math.floor(Math.random() * 6);

這段程式碼,是取[0,5]範圍的隨機整數,我們將floor改為round,簡單修改邏輯(因為四捨五入,這裡改為乘以5),檢視每五次取得數字的概率:

function randomArr() {
    let arr = [],
        length = 5;
    while (length--) {
        arr.push(Math.round(Math.random() * 5));
    };
    console.log(arr);
};
setInterval(function () {
    randomArr();
}, 1000);

如上圖,一眼掃下來出現0與5的概率,普遍比1,2,3,4要低,很明顯這對於0與5兩個邊界數字是不公平的。

2.使用ceil取整的問題

有了上面的分析,ceil就好理解多了,同樣是[0,5]範圍取隨機整數,我看同樣做範圍拆分。

由於是ceil是向上取整,只有是0時,才是0;只要超過0,0.1甚至0.0001都會向上取整變成1,同理,2,3,4,5概率都會相同,我們可以得出使用ceil對於0是極不公平的,我們將上面的程式碼中的round改為ceil:

想要隨機取整的數字是0的概率,簡直比中彩票頭等獎還低,畢竟0-1範圍內的隨機數字組合可以說無數個,外加上還有2,3,4,5幾個數字,這下總知道為啥不能用ceil了吧。

3.使用floor為什麼可以

floor因為是向下取整,0-0.999之前都是0,1-1.999之前都是1,每個數字概率相同。

所以我們取[0-5]範圍內整數時,使用的是Math.random() * 6,得到的範圍就是[0-5.999..],在通過下下取整,也就達到取[0-5]的目的了。

4.使用ceil取整後減去1模擬floor?

不對啊,向下取整概率相同,我向上取整不也一樣?求[0-5]範圍時,我能不能利用向上取整,求一個[1-6]再減去1呢?很明顯不行。

0.1-0.999向上取整是1,1.1-1.999向上取整是2,我們這個基礎上減去一個1,想法是好的,但這個想法忽略了比中彩票還難出現的數字0,只要0出現,我們根據通用想法減去1,那就是-1了。

Math.ceil(Math.random() * 6) - 1

這段程式碼貌似能正常取到0-5範圍的任意整數,其實當0出現時,就BUG了,雖然我們不知道0什麼時候會出現。

 肆 ❀ 總

那麼文章到這,我們大概知道了這幾個知識點:

1.round floor ceil的作用與區別

2.為什麼取範圍隨機整數使用floor而不是round或者ceil

3.利用floor的思想模擬了ceil減一的做法,結果行不通

那麼到這,算是給文章開頭的問題解答疑惑了,現在你知道為什麼不能使用round或者ceil取隨機整數了