在自我介紹時有提到,目前筆者正透過兩種管道在學習前端語言,在兩邊學習的過程中都遇到同一個情境——擲骰子:
Math.random()
表隨機回傳 0~1 之間的數(不含1)Math.random() * 6
隨機回傳 0~6 之間的數(不含6)Math.random() * 6 + 1
隨機回傳 1~7 之間的數(不含7),這時整數的部分確實都是 1~6 了,但把這個程式碼丟到主控台裡,會收到一堆小數點以後的數(骰子可擲不出來)Math.trunc(Math.random() * 6 + 1)
,一個是Math.floor(Math.random() * 6 + 1)
,兩個都能成功擲骰子!.
不同寫法,卻有相同結果總是會引發好奇,於是就開始找資料,有了以下的筆記
取整數,可以認識這四個程式碼 Math.trunc()
、Math.round()
、Math.round()
、Math.ceil()
Math.trunc()
回傳數字的整數部分,把小數點以後的部分通通捨去(筆者理解成「無條件捨去」)
Math.trunc(5.234) // expect return: 5
Math.trunc(5.876) // expect return: 5
Math.trunc(-5.234) // expect return: -5
Math.trunc(-5.876) // expect return: -5
Math.floor()
回傳小於或等於的最大整數
Math.floor(5.234) // expect return: 5
Math.floor(5.876) // expect return: 5
Math.floor(-5.234) // expect return: -6
Math.floor(-5.876) // expect return: -6
Math.ceil()
回傳大於或等於的最小整數
Math.ceil(5.234) // expect return: 6
Math.ceil(5.876) // expect return: 6
Math.ceil(-5.234) // expect return: -5
Math.ceil(-5.876) // expect return: -5
Math.round()
回傳最接近的整數(筆者理解成「四捨五入」)
Math.round(5.234) // expect return: 5
Math.round(5.876) // expect return: 6
Math.round(-5.234) // expect return: -5
Math.round(-5.876) // expect return: -6
筆者把Math.trunc()
理解成數學的無條件捨去,但許多資料筆記都寫著Math.floor()
是無條件捨去,他們的差異發生在負數,於是想起過去在學時很少會討論到負數的無條件捨去、無條件進位、四捨五入,就去查了一番定義... 以下擷取自Wiki - 數值簡化
無條件捨去:若所取位數之右有非0的數字,則一律無條件捨去。例如:23.7截尾後為23,−23.7截尾後為−23。正數取整後總是小於等於原數,負數取整後的數總是大於等於原數,因此「截尾取整」也稱「向原點方向取整」。
無條件進位:若所取位數之右有非0的數字,則一律無條件進位。例如:23.2取整後為24,−23.2取整後為−24。正數取整後總是大於等於原數,負數取整後總是小於等於原數,因此「無條件進位」也稱「遠離原點方向取整」或「正、負數各自向正、負無窮方向取整」。
四捨五入:若所取位數的位次後一位小於等於4,則捨去;反之,若大於等於5,則進位。若原數值為負數,則先以絕對值求得結果後再加負號。
結論:目前仍會把Math.trunc()
當成無條件捨去,Math.round()
當成四捨五入
Math.floor VS Math.trunc JavaScript
以上是今天的分享,謝謝看完的你!
使用 Math.round
能四捨五入至整數位,不過無法精確地四捨五入至小數位,使用 Number.prototype.toFixed
也是如此,舉例來說:
(2.005).toFixed(2); // 2.00
Math.round(1.005 * 100) / 100; // 1
無條件捨去正數時,會直接保留整數;無條件捨去負數時,會保留整數再減一。
再者,應該將 Math.trunc
理解為截斷(直接保留整數而沒有判斷),只有在操作正數時,才會等同於無條件捨去,舉例來說:
Math.floor(5.5); // 5
Math.floor(-5.5); // 6
Math.trunc(5.5); // 5
Math.trunc(-5.5); // -5
由此可知,只有 Math.floor
才能實現真正的無條件捨去,千萬不能將無條件捨去和截斷相提並論。
此外,實現截斷的方式不只有 Math.trunc
一個,舉例來說:
~~5.5; // 5
5.5 | 0; // 5
5.5 >> 0; // 5
Math.trunc(5.5); // 5
以上。
感謝 Felix 前輩!
是否可以理解成取到個位用 Math.round()
,取到小數後幾位用Number.prototype.toFixed()
?
原來還有「截斷」的概念存在!
但我會好奇根據 wiki 對「無條件捨去」的定義
若所取位數之右有非0的數字,則一律無條件捨去。例如:23.7截尾後為23,−23.7截尾後為−23。正數取整後總是小於等於原數,負數取整後的數總是大於等於原數,因此「截尾取整」也稱「向原點方向取整」。
Math.trunc()
是否比Math.floor()
來得更合適呢?
通常 Math.round
都是回傳整數,因此您的理解沒有問題,不過 Math.round
搭配乘除運算也能四捨五入至小數位,例如:
/* 四捨五入到整數個位 */
Math.round(2.005); // 1
/* 四捨五入到小數第二位 */
Math.round(2.005 * 100) / 100; // 2.01
然而,值得注意的是 Math.round
和 Number.prototype.toFixed
都有精度不足的問題,因此浮點數運算會有捨入誤差,例如:
Math.round(1.005 * 100) / 100; // 1
Math.round(2.005 * 100) / 100; // 2.01
數學運算理應不會產生捨入誤差,因此必須要考量捨入誤差所造成的影響。
無條件捨去和截斷很容易被誤認,因為它們只有在處理負數時,才會有不同的結果,例如:
Math.floor(-1.005); // -2
Math.trunc(-1.005); // -1
因此 Math.floor
和 Math.trunc
之間並沒有誰更合適的問題,實際使用取決於您的需求。
抱歉,一段時間沒有上線,希望能夠解答您的疑問!
非常感謝 Felix 前輩,儘管過了一段時間還願意來回覆!
經過你的說明後我有更加清楚可以如何更靈活的應用這些 method!也盡量讓自己不要太拘泥於「無條件捨去的定義」,而是如何讓程式碼達到需要的效果才是最重要的