0.1+0.2!==0.3
0.1 + 0.2 === 0.3 // false
计算机存储数字都是以多位二进制的方式进行存储的。
而 js 没有分浮点数和整数,全部统一为 number 类型,都利用 IEEE754 标准的 64 位双精度浮点数存储。
为什么会出现浮点数?
出现浮点数的原因是在牺牲计算精度的同时来提高存储数字的范围
浮点数的概念
浮点数的产生是二进制和十进制之间换算的过程中出现了问题
IEEE 754 浮点数由三个域组成,分别为 sign bit (符号位)、exponent bias (指数偏移值) 和 fraction (分数值)。
64 位中,sign bit 占 1 位,exponent bias 占 11 位,fraction 占 52 位。
通过公式表示浮点数的值:
当一个数为正数,sign bit 为 0,当为负数时,sign bit 为 1.
以 0.1 转换为 IEEE 754 标准表示为例解释一下如何求 exponent bias 和 fraction。转换过程主要经历 3 个过程:
- 将 0.1 转换为二进制表示
- 将转换后的二进制通过科学计数法表示
- 将通过科学计数法表示的二进制转换为 IEEE 754 标准表示
将 0.1 转换为二进制表示
0.1 的二进制表示为 0.00011...(无限重复 0011)
通过科学计数法表示
0.00011...(无限重复 0011) 通过科学计数法表示则是 ,其中小数位中无限重复1001
转换为 IEEE 754 标准表示
当经过科学计数法表示之后,就可以求得 exponent bias 和 fraction 了。
exponent bias (指数偏移值) 等于双精度浮点数固定偏移值 () 加上指数实际值(即 中的 -4) 的 11 位二进制表示。为什么是 11 位?因为 exponent bias 在 64 位中占 11 位。
因此 0.1 的 exponent bias 等于 的 11 位二进制表示,即 011 1111 1011。
再来获取 0.1 的 fraction,fraction 就是 1.10011001...(无限重复 1001) 中的小数位,由于 fraction 占 52 位所以抽取 52 位小数,1001...(中间有 11 个 1001)...1010 (请注意最后四位,是 1010 而不是 1001,因为四舍五入有进位,这个进位就是造成 0.1 + 0.2 不等于 0.3 的原因)。
到此,终于可以将 0.1 转换为 IEEE 754 表示了。
0 011 1111 1011 1001...( 11 x 1001)...1010
(sign bit) (exponent bias) (fraction)
2
3
因此不仅 0.1 会产生误差,0.2 及 0.3 也是如此,因此最后造成了 0.1 + 0.2 不等于 0.3 的结果。