1.背景
console.log(0.1 + 0.2) // 0.30000000000000004
console.log(0.4 - 0.1) // 0.30000000000000004
console.log(35.41 * 100) // 3540.9999999999995
console.log(1.02 / 5) // 0.20400000000000001
上述计算可得出结论,js计算中只要出现浮点数,就有可能出现 计算精度问题
2.思路
网上优秀的思路有很多,这里不一一说明。
我们的思路是,既然浮点数会导致精度问题,我们解决浮点数问题就好了。
- 获取参与计算的数字的小数点长度,以及一些其他所需的基础数据
- 将两数小数进行
移位处理,注意不是直接乘10/100/100,而是利用转化为string去掉'.',再转化为number - 针对每个计算方法特殊处理
3.代码实现
// 处理小数数据
const handlingDecimals = (x = 0, y = 0) => {
let lx, // x 小数点长度
ly, // y 小数点长度
lMax, // 最长小数点长度
strx, // x 字符串
stry, // y 字符串
intx, // x 去除小数点后的整数值
inty, // y 去除小数点后的整数值
divx, // x 转化为整数时扩大的倍数
divy, // y 转化为整数时扩大的倍数
divMax, // 最大转化为整数时扩大的倍数
divSum, // 乘法时总共扩大的倍数
divGap // 除法时两数相差倍数 要注意这里是计算 l = l被除数 - l除数
try {
strx = x.toString()
lx = strx.split('.')[1].length
} catch {
strx = 0
lx = 0
}
try {
stry = y.toString()
ly = stry.split('.')[1].length
} catch {
stringy = 0
ly = 0
}
lMax = Math.max(lx, ly)
intx = Number(strx.replace('.', ''))
inty = Number(stry.replace('.', ''))
divx = Math.pow(10, lx)
divy = Math.pow(10, ly)
divMax = Math.pow(10, lMax)
divSum = Math.pow(10, lx+ly)
divGap = Math.pow(10, ly - lx)
return {
lx, ly, lMax, divx, divy, divMax, divSum, divGap, strx, stry, intx, inty
}
}
// 乘 (小数转化为整数公共方法)
const multiply = (x = 0, y = 0) => {
const { intx, inty, divSum } = handlingDecimals(x, y)
return intx * inty / divSum
}
// 加
const addition = (x = 0, y = 0) => {
const { divx, divy, divMax } = handlingDecimals(x, y)
return (multiply(x, divx) + multiply(y, divy)) / divMax
}
// 减
const subtraction = (x = 0, y = 0) => {
const { divx, divy, divMax } = handlingDecimals(x, y)
return (multiply(x, divx) - multiply(y, divy)) / divMax
}
// 除
const division = (x = 0, y = 0) => {
const { intx, inty, divGap } = handlingDecimals(x, y)
return multiply(intx/inty, divGap)
}
4.测试用例
const resAddition = addition(0.1, 0.2) // 0.3
const resSubtraction = subtraction(0.4, 0.1) // 0.3
const resMultiply = multiply(35.41, 100) // 3541
const resDivision = division(1.02, 5) // 0.204
后续TODO
- 保留X位小数
- 函数封装&异常处理