使用 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

posted @ 2020-12-02 21:08  公瑾当年  阅读(6818)  评论(0编辑  收藏  举报