js小數點計算丟失精度

  有時需求中會有前端校驗輸入數字金額的時候,判斷,幾個輸入框的金額合計是否大於小於或等於某個整數,在輸入的值可以爲小數的時候,很容易就出現js小數點計算丟失精度問題。比如下圖

  js高級程序設計(我這版是第3版)在3.4.5Number類型這節中就談到了這個現象,原話是:

    關於浮點數值計算會產生攝入誤差的問題,有一點需要明確:這是使用基於IEEE754數值的浮點計算的通病,ESMAScript並非獨此一家,其他使用相同數值格式的語言也存在這個問題。

  所以即使浮點數值的最高精度是17位小數,但在進行算術計算時其精度遠遠不如整數。

  1.使用toFixed(x)方法,x爲必需,規定小數的位數,是 0 ~ 20 之間的值,包括 0 和 20,如果省略了該參數,將用 0 代替。

  比如:

   但是這種方法的侷限性是不能使用toFixed(x)去進行舍入操作。因爲IEEE754標準規定的浮點數取整算法是銀行家舍入法,即四捨六入五留雙法:四捨六入五考慮,五後非零就進一,五後爲零看奇偶,五前爲偶應捨去,五前爲奇要進一。

  早期的時候似乎在不同瀏覽器會有不同的表現,但是現在基本上大部分瀏覽器都是toFixed(x)遇5不會進1,而是直接捨去,可能也和chrome內核一家獨大有關係。在Chrome瀏覽器中的控制檯表現如下:

  精度只能用於所有操作數中最多小數位的精度計算,即toFixed(x)中的x必須大於等於最多小數位操作數的小數位數量,否則就會丟失精度。

  2.使用第三方庫

  比如Math.js,decimal.js,使用方法大同小異,詳情見:

  https://www.npmjs.com/package/mathjs

  https://www.npmjs.com/package/decimal.js/v/3.0.0

  以vue2.x爲例:

  先npm install mathjs / decimal.js

  然後在main.js中引入,以ES模塊規範爲例:

  math.js是這樣使用的:(詳見math.js文檔:https://mathjs.org/docs/index.html)

import * as math from "mathjs";

const config = {
  epsilon: 1e-12,
  matrix: 'Matrix',
  number: 'number', //運算時需要精度準確時此處需配置爲BigNumber
  precision: 64, //僅在number類型爲BigNumbers生效
  predictable: false,
  randomSeed: null //選項設置爲種子僞隨機數生成,使其成爲確定性的。
}
const math = create(all, config);

let number = math.add(math.bignumber(0.1), math.bignumber(0.2)); //操作數中至少要有一個調用bignumber()

  decimal.js是這樣使用的:(詳見decimal.js文檔:http://mikemcl.github.io/decimal.js/)

import { Decimal } from 'decimal.js';

let number = new Decimal(0.11).add(new Decimal(0.29));

其他

  本來到前面就到尾聲了,但是這裏還是需要囉嗦一下,我還看過一些博客還提到一個方法或是自己封裝的方法,其核心是先將小數*10的n次方放大爲整數,只要最終結果在Number類型邊界之內的整數運算是不會有精度誤差的,然後再將整數的運算結果除於10的n次方就得到最終的結果。但是,這個方法沒寫好也是存在問題的,就比如前面舉的例子:0.07*100,結果就不是7。因爲只有少數幾個小數可以被浮點數精確表示,比如0.25的N次方,或是0.75的n次方,其他的小數基本都是近似數。其實我也很納悶0.06,0.08也都是近似數,但是他們相乘100結果分別就是6,8。有些博主通過這個方法封裝的方法都沒考慮到這塊,所以在相乘放大過程中就已經出錯了,但是如果在放大縮小過程中能控制住精度,也仍不失爲一個解決問題的好方法。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章