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了
解决方案:
- 使用Number.toFixed()将小数的位数进行限制,减小精度误差的出现

- 封装一个方法用于计算,先将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中的Number类型使用双精度浮点型表示,导致小数计算时存在精度问题,主要体现在小数转二进制的乘二取整过程中。这种精度丢失在0.1+0.2不等于0.3的例子中尤为明显。解决办法包括使用Number.toFixed()限定小数位数,或者借助如bignumber.js等第三方库进行高精度计算。
1207





