[转]使用 mathjs 解决 js 小数精度问题
原文地址:使用 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