一、背景
当涉及到浮点数计算时,js 中的精度丢失问题, 是由于使用 IEEE 754 标准来表示和计算浮点数的方式引起的。这个问题不仅仅在 js 中存在,而是在所有使用 IEEE 754 标准的编程语言中都会遇到。
IEEE 754 标准定义了两种常见的浮点数表示形式:单精度(32 位)和双精度(64 位)。在 js 中,采用的是双精度表示法,即 64 位。
然而,由于二进制和十进制之间的转换存在差异,某些十进制分数无法精确表示为有限位的二进制浮点数。这导致了舍入误差和精度丢失。
二、解决方案
使用 big.js 进行计算,而不是直接加减乘除
安装依赖
1
| npm install --save big.js
|
方法封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import Big from 'big.js'
export function createFactory(method = 'add') { return function (...nums) { nums = nums.map(Number).filter((num) => num || num === 0) if (nums.length < 2) return nums[0] || 0 return parseFloat(nums.slice(1).reduce((prev, num) => prev[method](num), new Big(nums[0]))) || 0 } }
`plus、minus、times、div为big.js中的计算方法,分别对应加减乘除这四个运算操作`
`浮点数求和` export const secureAdd = createFactory('plus') `浮点数相减` export const secureSub = createFactory('minus') `浮点数相乘` export const secureMul = createFactory('times') `浮点数相除` export const secureDiv = createFactory('div')
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { secureAdd, secureSub, secureMul, secureDiv } from '@/utils/calculate'
mounted() { this.calTestHandler() },
methods: { calTestHandler() { const operations = [ { operator: '+', method: secureAdd, a: 0.1, b: 0.2 }, { operator: '-', method: secureSub, a: 0.1, b: 0.3 }, { operator: '*', method: secureMul, a: 0.1, b: 0.2 }, { operator: '/', method: secureDiv, a: 0.1, b: 0.3 } ]
operations.forEach((operation) => { const { operator, method, a, b } = operation const result = method(a, b) console.log(`原生js ${operator} 运算:${a} ${operator} ${b}的值是${eval(a + operator + b)}`) console.log(`big.js ${operator} 运算:${a} ${operator} ${b}的值是${result}`) }) } }
|
结果展示: