iT邦幫忙

1

2022 鐵人賽|Day2 【JavaScript】取整數

Kim 2022-09-17 21:23:113126 瀏覽
  • 分享至 

  • xImage
  •  
附上為何鐵人賽文章會出現在這裡的說明:2022 鐵人賽|Day1 報名失敗,還是要開賽吧!

背景脈絡

在自我介紹時有提到,目前筆者正透過兩種管道在學習前端語言,在兩邊學習的過程中都遇到同一個情境——擲骰子:

  1. 使用Math.random()表隨機回傳 0~1 之間的數(不含1)
  2. Math.random() * 6隨機回傳 0~6 之間的數(不含6)
  3. 由於骰子是要丟出 1~6 的整數,所以Math.random() * 6 + 1隨機回傳 1~7 之間的數(不含7),這時整數的部分確實都是 1~6 了,但把這個程式碼丟到主控台裡,會收到一堆小數點以後的數(骰子可擲不出來)
  4. 我們只要整數的部分,卻在兩邊教材看到了不同的做法,一個是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


以上是今天的分享,謝謝看完的你!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Felix
iT邦研究生 2 級 ‧ 2022-09-20 01:43:24

四捨五入

使用 Math.round 能四捨五入至整數位,不過無法精確地四捨五入至小數位,使用 Number.prototype.toFixed 也是如此,舉例來說:

(2.005).toFixed(2); // 2.00
Math.round(1.005 * 100) / 100; // 1

無條件捨去 versus 截斷

無條件捨去正數時,會直接保留整數;無條件捨去負數時,會保留整數再減一。

再者,應該將 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

以上。

Kim iT邦新手 4 級 ‧ 2022-09-20 08:12:22 檢舉

感謝 Felix 前輩!

四捨五入

是否可以理解成取到個位用 Math.round(),取到小數後幾位用Number.prototype.toFixed()

捨去 vs 截斷

原來還有「截斷」的概念存在!

但我會好奇根據 wiki 對「無條件捨去」的定義

若所取位數之右有非0的數字,則一律無條件捨去。例如:23.7截尾後為23,−23.7截尾後為−23。正數取整後總是小於等於原數,負數取整後的數總是大於等於原數,因此「截尾取整」也稱「向原點方向取整」。

Math.trunc()是否比Math.floor()來得更合適呢?

Felix iT邦研究生 2 級 ‧ 2023-03-25 00:42:28 檢舉

Kim

通常 Math.round 都是回傳整數,因此您的理解沒有問題,不過 Math.round 搭配乘除運算也能四捨五入至小數位,例如:

/* 四捨五入到整數個位 */
Math.round(2.005); // 1

/* 四捨五入到小數第二位 */
Math.round(2.005 * 100) / 100; // 2.01

然而,值得注意的是 Math.roundNumber.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.floorMath.trunc 之間並沒有誰更合適的問題,實際使用取決於您的需求。


抱歉,一段時間沒有上線,希望能夠解答您的疑問!

Kim iT邦新手 4 級 ‧ 2023-04-04 17:46:11 檢舉

非常感謝 Felix 前輩,儘管過了一段時間還願意來回覆!
經過你的說明後我有更加清楚可以如何更靈活的應用這些 method!也盡量讓自己不要太拘泥於「無條件捨去的定義」,而是如何讓程式碼達到需要的效果才是最重要的

我要留言

立即登入留言