原因
JavaScript只有一种数字类型:Number,它的实现遵循IEEE 754标准,使用64位固定长度表示(标准的double双精度浮点数)。在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位。剩余的遵从‘0舍1入’原则舍去。 0.1 的二进制值是个无限循环小数,精度丢失,所以 0.1 + 0.2 !== 0.3。
整数的十进制转二进制的规则:
整数
÷2取余,倒序排列,高位补0(计算机内部表示数是定长的:8位、16位、32位)。
负整数
- 把正整数转成二进制
- 对二进制取反
- 对取反后的二进制加1(补码?)
小数
- 小数部分*2
- 取结果的整数部分
- 结果的小数部分*2
- 取结果的整数部分
- 直到小数部分为0或者位数与小数位数到达一定精度
- 正序排列 0.1和0.2都是无限循环的,存储时只能通过近似值存储,造成误差。
解决
toFixed()
toFixed() 方法可把 Number 四舍五入为指定小数位数的数字
(0.1+0.2).toFixed(4)===0.3.toFixed(4)
设置误差范围(机器精度)——Number.EPSILON
x = 0.2;
y = 0.3;
z = 0.1;
equal = (Math.abs(x - y + z) < Number.EPSILON);
Number.EPSILON 属性表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值。
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16,或者 2^-52。