使用 mathjs 解決 js 小數精度問題


很經典的例子是0.1+0.2!=0.3(實際等於 0.30000000000000004)

不等的原因

機器中采用二進制存儲數據,

比如,35會被存儲為: 00100011 (2^5 + 2^1 + 2^0)。
0.375會被存儲為: 0.011 (1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375)

而對於像0.1轉換為二進制表示,就會發現無法整除,算下來會是 0.00011001100110011...(0011無限循環)

0.2轉換為二進制為:0.001100110011...(0011無限循環)

由於存儲空間有限,計算機會舍棄后面的數值,所以機器中存儲的就是一個近似值。

而以近似值為基礎進行運算,則會出現結果0.30000000000000004的情況

對於JS來說,其不夠近似於0.3,於是就出現了0.1 + 0.2 != 0.3 這個現象。 當然,也並非所有的近似值相加都得不到正確的結果。有時兩個近似值進行計算的時候,得到的值是在JS的近似范圍內的,於是就可以得到正確答案。

Reat項目引用Math.js處理浮點數精度問題

我們借助 Math.js 這個庫來處理浮點數的精度問題

下載

npm install mathjs

在react中引入並配置

import { create, all } from 'mathjs'
const config = {
    epsilon: 1e-12,
    matrix: 'Matrix',
    number: 'BigNumber', // 可選值:number BigNumber
    precision: 64,
    predictable: false,
    randomSeed: null
}
const math = create(all, config)
  • 用靜態函數和常數(就像JavaScript的Math對象)

    math.round(math.e, 3);            // 2.718
    math.add(2, 3);  // 5 
    math.sqrt(-4);  // 2i 
    math.pow([[-1, 2], [3, 1]],2);     // [[7, 0], [0, 7]]
    math.derivative('x^2 + x', 'x');  // 2 * x + 1
    math.atan2(3, -3) / math.pi;      // 0.75
    
  • 對字符串表達式進行求值運算

    math.evaluate('12 / (2.3 + 0.7)');    // 4
    math.evaluate('12.7 cm to inch');     // 5 inch
    math.evaluate('sin(45 deg) ^ 2');     // 0.5
    math.evaluate('9 / 3 + 2i');          // 3 + 2i
    math.evaluate('det([-1, 2; 3, 1])');  // -7
    

在對字符串表達式進行求值計算的時候,計算的結果是 mathjs 定義的類型,我們可以將其轉換成 字符串 以得到正常的結果

  • 鏈式操作

    math.chain(3)
        .add(4)
        .multiply(2)
        .done(); // 14
    
  • 矩陣操作

    var n = math.matrix([[4,3,2], [6,6,8], [7,4,5]]);   
    console.log(n.valueof()); // [[4,3,2],[6,6,8],[7,4,5]]
    

    注:大多數math.js函數,都需要valueof()或者done()函數來真正地獲取操作的值,如上面代碼所示。

注意

  • 如果 config 配置項中的 number 屬性值設為 number,那么仍然會有精度問題

    math.add(0.1, 0.2) // 0.30000000000000004
    
    加:math.format(math.add(math.bignumber(1.1),math.bignumber(2.2))) // 3.3
    
    減:math.format(math.subtract(math.bignumber(1.1),math.bignumber(2.2)))
    
    乘:math.format(math.multiply(math.bignumber(1.1),math.bignumber(2.2)))
    
    除:math.format(math.divide(math.bignumber(1.1),math.bignumber(2.2)))
    
    

    bignumber() 方法是進行數值類型聲明,即表示該數值類型是浮點數,需要進行精度計算

  • 當為 config 配置項中的 number 屬性值設置 BigsNumber 之后,能夠解決精度問題。

    math.format(math.evaluate('1.1+2.2')) // 3.3 --> string 類型
    

    format()方法是格式化校驗方法,把math方法計算出的值以字符串的形式顯示最終的結果

參考文章:

https://www.jianshu.com/p/96c90f03679d

https://www.jianshu.com/p/4f63f0003a56

https://zhuanlan.zhihu.com/p/148270821

vue 中使用mathjs


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM