cklwblove / blog

记录日常遇到的bug
1 stars 0 forks source link

加减乘除运算集成`big.js`,解决js小数精度问题 #126

Open cklwblove opened 1 year ago

cklwblove commented 1 year ago

前提: 当涉及到浮点数计算时,js中的精度丢失问题, 是由于使用IEEE 754标准来表示和计算浮点数的方式引起的。这个问题不仅仅在js中存在,而是在所有使用IEEE 754标准的编程语言中都会遇到。

IEEE 754标准定义了两种常见的浮点数表示形式:单精度(32位)和双精度(64位)。在 js中,采用的是双精度表示法,即64位。

然而,由于二进制和十进制之间的转换存在差异,某些十进制分数无法精确表示为有限位的二进制浮点数。这导致了舍入误差和精度丢失。

安装依赖: npm install --save big.js 方法封装:

import Big from 'big.js'

export function accFactory(method = 'add') {
  return function (...nums) {
   // `将传入的参数转换为Number类型,并过滤掉不是Number类型的结果`
    nums = nums.map(Number).filter((num) => num || num === 0)
   // `如果过滤后的结果是长度为1的数组,那就返回数组的第一项`
   // `如果过滤后的结果为空数组,则返回0`
    if (nums.length < 2) return nums[0] || 0
   // `需要为reduce方法赋初值,是因为big.js的运算操作,是基于new Big格式的数字`
   // `可以将Big对象转换为浮点数,方便后续Number.toFixed()的操作`
    return parseFloat(nums.slice(1).reduce((prev, num) => prev[method](num), new Big(nums[0]))) || 0
  }
}

// `plus、minus、times、div为big.js中的计算方法,分别对应加减乘除这四个运算操作`

// `浮点数求和`
export const accAdd = accFactory('plus')
// `浮点数相减`
export const accSub = accFactory('minus')
// `浮点数相乘`
export const accMul = accFactory('times')
// `浮点数相除`
export const accDiv = accFactory('div')

测试:

mport { accAdd, accSub, accMul, accDiv } from '@/utils/calculate'

mounted() {
  this.calTestHandler()
},

methods: {
  calTestHandler() {
    const operations = [
      { operator: '+', method: accAdd, a: 0.1, b: 0.2 },
      { operator: '-', method: accSub, a: 0.1, b: 0.3 },
      { operator: '*', method: accMul, a: 0.1, b: 0.2 },
      { operator: '/', method: accDiv, 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}`)
    })
  }
}

-- 摘自:https://mp.weixin.qq.com/s?__biz=Mzg2NjY2NTcyNg==&mid=2247490119&idx=1&sn=6a6094cb61234160d5430cc6245b5211&chksm=ce460fd6f93186c0e5c696b33cfe0ae739ad077139eabcc263bf4742b9f0289c1a4cce5da4ce#rd