JS中0.1+0.2 !== 0.3的原因以及如何解决此问题

1. 0.1+0.2 !== 0.3 的原因

在 js 中进行数学运算时,会出现0.1+0.2=0.300000000000000004的结果,刚开始以为原因是浮点数的二进制存储导致的精度问题,但这并不能为什么在同样的存储方式下0.3+0.4=0.7。

原因:

(1)JavaScript遵循IEEE754标准,在64位中存储一个数据的有效数字形式。其中第0位符号位,0表示正数1表示负数,第1到11位存储指数部分,第12到63位小数部分(即有效数字)。
二进制的有效数字总是表示为 1.xxx…的形式,尾数部分在规约形式下的第一位默认为1,因此存储时第一位省略不写,尾数部分f存储有效数字小数点后的xxx…,最长52位。JavaScript提供的有效数字最长为53个二进制位(尾数部分52位+被省略的1位)。
(2)对阶运算
指数位数不同,运算时需要进行对阶运算。0.1+0.2与0.3+0.4的尾数求和结果:

0.1+0.2->10.0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0111
0.3+0.4->10.1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101

求和结果需规格化(有效数字表示),右规导致低位丢失,此时需对丢失的低位进行舍入:

0.1+0.2->1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 1->1.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0100 ()
0.3+0.4->1.0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 1->1.0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 ()

00111->0100
01101->0110
0.3+0.4对阶阶运算且规格化后的运算结果与0.7在二进制中的存储尾数相同(可对照尾数后几位),而0.1+0.2的运算结果与0.3的存储尾数不同,且0.1+0.2转化为十进制时结果为0.300000000000000004。
(3)IEEE754标准下的舍入规则
维基百科对最近偶数舍入原则的解释如下:舍入到最接近,在一样接近的情况下偶数优先(Ties To Even,这是默认的舍入方式),即会将结果舍入为最接近(精度损失最小)且可以表示的值,但是当存在两个数一样接近的时候,则取其中的偶数(在二进制中是以0结尾的)。

2. 解决方法

(1)先转换成整数,再相加之后转回小数:

let a = (0.1*10+0.2*10)/10;
console.log(a===0.3)

(2)使用es6新增的Number.EPSILON方法:

const handlerMath = (a, b) => {
 	return Math.abs(a - b) < (Number.EPSILON ? Number.EPSILON : Math.pow(2, -52));
}
console.log(handlerMath(0.1 + 0.2, 0.3))

(3)使用number对象的toFixed方法,toFixed方法可以指定运算结果的小数点后的指定位数的数字,使保留一位小数就是toFixed(1):

let a = parseFloat((0.1+0.2).toFixed(1));
console.log(a === 0.3);
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值