你是不是一直都默認 Math.round
是四捨五入呢,我一直以來也是,直到最近我處理到toFixed
的問題時好奇跑過來嘗試 Math.round
,發現事情不是我想的那樣,至於toFixed
有啥問題那又是另一回事了。
先來看看維基百科的描述
四捨五入 若所取位數的位次後一位小於等於4,則捨去;反之,若大於等於5,則進位。若原數值為負數,則先以絕對值求得結果後再加負號。
我們再來嘗試 Math.round
,你會發現有一個的結果跟用維基百科做完的運算其實不同
Math.round(1.4) // 1
Math.round(1.5) // 2
Math.round(1.6) // 2
Math.round(-1.4) // -1
Math.round(-1.5) // -1 ?
Math.round(-1.6) // -2
後來去 MDN 看也有段在描述這件事,但實際上只是提醒並沒有跟妳說為什麼,那想當然最後的手段就是去 ecmascript 找規格描述。
撇除前面的數值檢查只看最後一個步驟「Return the integral Number closest to n, preferring the Number closer to +∞ in the case of a tie.」
想辦法找到一個最接近 n 的整數,如果有兩個整數與 n 距離相同也最接近,選接近正無限的那個整數。
如何快速找到這個整數呢,其實很單純,先將 n
去掉小數點(這裡先取名為 int_n
)如果是正數就是 int_n
, int_n + 1
,如果是負數就挑 int_n
, int_n - 1
,如果你想保險一點就在減一或加一。
再來就是用你挑好的整數與 n
相減取絕對值然後比誰最小,如果距離相同選最接近正無限的那個整數,這裡用 1.5
舉例
- 找到最接近
n
的整數,這裡就會是1
,2
- 將挑好的整數與
n
相減取絕對值然後比誰最小|1 - 1.5| = 0.5
|2 - 1.5| = 0.5
- 兩個結果相同就選最接近正無限的整數,所以這裡最後會選
2
,答案就是2
我們將這個公式套到那個有問題的數值上,也就是 -1.5
- 找到最接近
n
的整數,這裡就會是-1
,-2
- 將挑好的整數與
n
相減取絕對值然後比誰最小|-1 - (-1.5)| = 0.5
|-2 - (-1.5)| = 0.5
- 兩個結果相同就選最接近正無限的整數,所以這裡最後會選
-1
,答案就是-1
聰明的你肯定發現的這個公式跟維基百科寫的似乎不同,少了先取絕對值再做運算的動作,不過就算沒取絕對值,也應該在 n
為負數時與 n
等距的整數上挑最接近負無限的那個。
這是怎麼一回事呢,我不得而知,反正被我無意間發現了,如果沒特別去驗證,我大概永遠不會發現。