js中小数计算时精度问题

js中的number为双精度浮点型,计算时需要先进行进制转换,将十进制换成二进制,而进制转换时,小数就有可能出现精度问题了,原因如下

整数转二进制:除二取余法(没有问题)
4 除以 2 取余数直到商为0
4/2 = 2……0
2/2 = 1……0
1/2 = 0……1
反向取余数得到
4 ----》100 = 1 * 2 ^ 2 + 0 * 2 ^ 1 + 0 * 2 ^ 0

小数转二进制:乘二取整法(精度丢失)
0.1 乘 2 取整数直到积为整数
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
然后一直重复……
所以取整数部分得到
0.1 ----》0.000110……(无限循环)
双精度浮点型是用64位二进制存储的,意味着这里会有0舍1入的精度丢失,这就能解释为什么0.1+0.2 !=0.3了

解决方案:

  1. 使用Number.toFixed()将小数的位数进行限制,减小精度误差的出现
    toFixed
  2. 封装一个方法用于计算,先将number转化为整数
function calulate(firstNumber, secondNumber, symbol) {
  symbol = symbol || '+'
  let firstDecimal = firstNumber.toString().indexOf('.') != -1 ? firstNumber.toString().split('.')[1].length : 0
  let secondDecimal = secondNumber.toString().indexOf('.') != -1 ? secondNumber.toString().split('.')[1].length : 0
  let maxDecimal = secondDecimal > firstDecimal ? secondDecimal : firstDecimal
  let result = 0
  let firstInt = parseInt(firstNumber.toString().replace('.','')) * Math.pow(10, (maxDecimal-firstDecimal))
  let secondInt = parseInt(secondNumber.toString().replace('.','')) * Math.pow(10, (maxDecimal-secondDecimal))
  switch (symbol) { 
    case '+':
      result = firstInt + secondInt
      return result / Math.pow(10, maxDecimal)
      break
    case '-':
      result = firstInt - secondInt
      return result / Math.pow(10, maxDecimal)
      break
    case '*':
      result = firstInt * secondInt
      return result / Math.pow(10, maxDecimal*2)
      break
    case '/':
      return result = firstInt / secondInt
      break
    default:
      result = firstInt + secondInt
      return result / Math.pow(10, maxDecimal)
      break
  }
}

3.可以用第三方封装类库,比如bignumber.js等

你可能感兴趣的:(javascript)