javaScript 中 toFixed() 精度問題及解決方案

昨天工作中發現了一個問題,是后端計算的成交價和前端計算的成交價有時候會有一分錢的差異,后來發現是由于 toFixed 的方法存在差異。

在 C# 中的取舍方法使用的是銀行家舍入法,也就是四舍六入五取偶(又稱四舍六入五留雙)。在 javaScript 中 Number.prototype.toFixed()的方法在四舍和六入上沒什么爭議,而當判斷位為5的時候就顯得有點奇怪。

銀行家舍入法

據說,大部分的編程軟件都使用的是這種方法,也算是一種國際標準。 所謂銀行家舍入法,其實質是一種四舍六入五取偶(又稱四舍六入五留雙)法。其規則是:當舍去位的數值小于5時,直接舍去該位;當舍去位的數值大于等于6時,在舍去該位的同時向前位進一;當舍去位的數值等于5時,如果前位數值為奇,則在舍去該位的同時向前位進一,如果前位數值為偶,則直接舍去該位。

以下是各個瀏覽器中測試 toFixed() 的結果:

Chrome:

Chrome 下的 toFixed

FireFox:

FF 下的 toFixed

IE:

IE 下的 toFixed

可以看出在不同瀏覽器中,toFixed方法都給出了不同的結果,讓人摸不到頭腦。

于是我查詢了 ECMA 里Number.prototype.toFixed() 的規范,如下:

?ECMA-262?Number.prototype.toFixed()

拿 0.15 和 10.15 舉個栗子。

(0.15).toFixed(1)

num = 0.15; f = 1;

根據步驟 10.a :

2 ÷ 10^f - num? ? ? ? // 0.05000000000000002

1 ÷?10^f - num? ? ? ? // -0.04999999999999999

取最接近 0 的值,得 (0.15).toFixed(1) 返回 0.1。

(10.15).toFixed(1)

num = 10.15; f = 1;

根據步驟 10.a :

102 ÷?10^f - num? ? ? ? //? 0.049999999999998934

101 ÷?10^f - num? ? ? ? //?-0.05000000000000071

取最接近 0 的值,得 (10.15).toFixed(1) 返回 10.2。

歸根到底就是浮點數精度的鍋。


找到原因后,我想到了兩種解決方案:

使用Math.round()

用這個方法可以實現傳統的四舍五入。

通過 Math.round() 來實現傳統四舍五入


重寫Number.prototype.toFixed()

這個方法則是更加公平的四舍六入五取偶。

重寫 Number.prototype.toFixed()

重寫后的結果:

重寫后在 Chrome 上的結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 個人學習批處理的初衷來源于實際工作;在某個迭代版本有個BS(安卓手游模擬器)大需求,從而在測試過程中就重復涉及到...
    Luckykailiu閱讀 4,761評論 0 11
  • 一、JS數字精度丟失的一些典型問題 1. 兩個簡單的浮點數相加1 0.1 + 0.2 != 0.3// true ...
    a180754bf396閱讀 6,692評論 0 0
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,754評論 18 399
  • [TOC] 第四周會議 歡迎J的加入 陳杰主要后臺開發 本周大家的進度 溫江濤: 本周拉進大黑,然后還是看書。周末...
    累了就歇一會_繼續出發閱讀 244評論 0 1
  • 寫在前面 態度決定高度!讓優秀成為一種習慣! 世界上沒有什么事兒是加一次班解決不了的,如果有,就加兩次!(- - ...
    夜盡天明時閱讀 4,583評論 3 9