两小数相加,解决JS两数相加的精度问题
前言
加入博客3年,第一次写文章,实在对自己有点无语!但对于前端的学习自己还是个初学者,希望能坚持,加油学习。话不多说,开始第一次。
JS中小数相加存在的精度问题
首先来看一段示例:
console.log(0.1+0.2);//0.30000000000000004
console.log(0.2+0.7);//0.8999999999999999
JS中两数小数相加产生精度问题的原因:
1、js中的数字类型只有number类型,不区分浮点型和整形,直接以浮点型double类型(双精度浮点类型)参与运算。
2、十进制数在做加减法运算前,首先转换为二进制类型再做相加减运算。
3、一些浮点数在转换为二进制数是会出现无线循环的情况,但由于double数据类型是以64位存储表示一个数据,其中第1位为符号位,第2位到第12位为指数位,其余52位为小数位,如此一来,一些浮点数转换为二进制产生无限循环的情况下,double类型数据只能存储64位,所以产生精度缺失问题。
关于浮点数转换为二进制数缺失精度问题的具体原因请参考以下文章:https://www.cnblogs.com/zm-blogs/p/12909096.html
解决办法
该方法仅为其中一个办法:
<script>
// 精确乘法计算
function FloatMul(arg1, arg2) {
var m = 0,
s1 = arg1.toString(),//将第一个数据转换成字符出类型
s2 = arg2.toString();//将第二个数据转换成字符出类型
try {
m += s1.split(".")[1].length;//截取数据的小数部分,得到小数位数
} catch (e) {}
try {
m += s2.split(".")[1].length;//截取数据的小数部分,得到小数位数
//将两个数据的小数位数长度相加
} catch (e) {}
var result = (Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) / Math.pow(10, m);//将两个数扩大对应的小数位数倍转换成数字类型在相乘,乘完再除于对应的扩大倍数得到最终结果
return isNaN(result) ? 0 : result;
}
//获得两个小数相加的精确值
const accountAdd = (arg1, arg2) => {
let r1, r2, m;
try {
r1 = arg1.toString().split(".")[1].length;//将第一个数据转换成字符出类型,截取数据的小数部分,得到小数位数
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;//将第一个数据转换成字符出类型,截取数据的小数部分,得到小数位数
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));//取出得到的最长位数,将10扩大最长位数倍
return (FloatMul(arg1, m) + FloatMul(arg2, m)) / m;
};
let sum = accountAdd(2.3443, -1.987);
console.log(sum);//0.3573
</script>
思路:
1、先将两个小数数据用精确乘法扩大相同倍数,扩大后相加再处于扩大倍数得到最后结果。
疑惑:使用精确加法也可以将两个小数数据扩大相同倍数,但在项目中做试验,数据量大的时候还是会存在精度问题,所以加了精确乘法运算在里边,具体原因还没搞明白!!!
此解决方法参照了其他博主的文章,但没收藏找不到链接了,请原博主谅解!