0.1 + 0.2 不是等于 0.3的原因,以及处理方法

原因

js中的数字

JavaScript的Number类型为双精度IEEE 754 64位浮点类型。

那么一个Number的二进制的形态为

  • 第0位:符号位,0表示正数,1表示负数(s)
  • 第1位到第11位:储存指数部分(e)
  • 第12位到第63位:储存小数部分(即有效数字)f

JS中Number的最大安全整数为(2^52 -1) = 4503599627370495 是一个16位的整数,因此当我们赋值大于安全整数的一个Number给一个变量的时候,那么到输出的时候就会得到的值和我们赋予的值不同,

 二进制的转换

由于JavaScript的Number类型为双精度IEEE 754 64位浮点类型,因此当JS要表示一个数字的时候需要进行二进制的转换

整数转二进制

除2 (取余)

例如 21  得 10101 如果计算机是8位 16位 32位 64位 不够的就往前补0

21 /2 ----------余  1
10/2  ----------余  0
5/2   ----------余  1
2/2   ----------余  0
1/2   ----------余  1

负整数转二进制

先是将对应的正整数转换成二进制后,对二进制取反(0-1对调),然后对结果再加一

例子 -21 得 01011

21 的二进制表示为: 10101
取反:  01010
加一 : 01011

二进制中 0+1 = 1 ; 1+0 = 1; 1+1 = 10  就相当于进一位

十进制(小数)转二进制

乘2(取整)

例如 0.125 得0.001

0.125×2=0.25 ---> 0

0.25×2=0.5 ---> 0

0.5×2=1.0 ---> 1

例如:0.1 得 0.000110.... 答案是一个无线的小数

    0.1 * 2 = 0.2  --->  0
    0.2 * 2 = 0.4  --->  0
    0.4 * 2 = 0.8  --->  0
    0.8 * 2 = 1.6  --->  1
    0.6 * 2 = 1.2  --->  1
    0.2 * 2 = 0.4  --->  0
    .....

因此

转换网址

0.1 -> 0.0001100110011001...(无限循环)

0.2 -> 0.0011001100110011...(无限循环)

但是由于IEEE 754尾数位数限制,需要将后面多余的位截掉,截取后精度发生了一些变化,然后在(二进制的相加对阶运算)2个都有精度变化的0.1+0.2就很不幸运的成为了0.30000000000000004....

但是由于我们前面有提到尾数f的固定长度是52位,是4503599627370495 是一个16位的整数,所以JS会有一个类似 toPrecision(16) 来做精度运算,0.30000000000000004....就被截取为了0.30000000000000004,所以0.1+0.2!===0.3,

总结原因就是:精度损失可能出现在进制转化和对阶运算过程中

解决方法

console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值