背景
JS中的数字采用 IEEE 754 标准的 64 位双精度浮点数,十进制的数值在进行计算时都会被转换成二进制,但由于浮点数用二进制表达时是无穷的,采用二进制进行计算后再转回十进制,就会产生误差。当然这类问题不只是在JS中才有,JAVA等强类型语言也存在。
关于精度丢失,大家通常都知道的是0.1 + 0.2 = 0.30000000000000004。本来我想着一个两位小数的浮点数,乘上100不会出现精度丢失的问题,直到我遇到了19.9 * 100,你可以试试,所以我现在对浮点数的计算都采取不信任的处理方式。
解决
mathjs与bigjs这两个库流行很久了,在处理这方面问题上也很专业。下面是我采用mathjs封装的方法:
import * as math from 'mathjs' // 处理浮点数问题
const config = { // 配置
epsilon: 1e-12,
matrix: 'Matrix',
number: 'BigNumber',
precision: 64,
predictable: false,
randomSeed: null
}
const roya = math.create(math.all, config)
export function add(arg1, arg2) {
return +roya.add(roya.bignumber(arg1), roya.bignumber(arg2)).valueOf()
}
export function subtract(arg1, arg2) {
return +roya.subtract(roya.bignumber(arg1), roya.bignumber(arg2)).valueOf()
}
export function multiply(arg1, arg2) {
return +roya.multiply(roya.bignumber(arg1), roya.bignumber(arg2)).valueOf()
}
export function divide(arg1, arg2) {
return +roya.divide(roya.bignumber(arg1), roya.bignumber(arg2)).valueOf()
}
因为valueOf方法返回的是字符串类型,所以我直接用+号转数字类型了。