国际标准IEEE 754告诉你为什么01.+02 !== 0.3

420 阅读4分钟

在js中采用IEEE 754 标准来存储浮点数且只使用64位双精度来表示浮点数

1.png

对于64位的浮点数,最高的1位是符号位 S,接着 11位是指数 E,剩下的52位是尾数位 M 即国际标准IEEE 754,任意一个二进制浮点数V可以用以下公式计算: 2.png

  • 符号位 S:0 表示正数,1表示负数
  • 指数 E:表示次方(2^E),指数E是一个无符号整数,11位的E取值范围是0 ~ 2047。但科学计数法中的E可以出现负数,所以IEEE 754规定,E的真实值必须再减去一个中间数,对于11位的E,这个中间数是1023。如2^10的E是10,保存为64位浮点数时,必须保存为10+1023的二进制数 指数E的三种情况:
  • E不全为0或者不全为1,浮点数采用上面的规则表示,指数E的计算值加上1023,得到真实值,再将有效数字M前加上第一位的1;
  • E全为0,浮点数的指数E等于-1023,有效数字M不再加上第一位的1,而是还原为0.xxx的小数。这个做是为了表示±0,以及接近于0很小的数字
  • E全为1,如果M全为0,便是正负无穷大(±由符号位确定);如果有效数字M不全为0,表示这个数不是一个数(NaN)
  • 尾数 M:表示有效数字,IEEE 754中, 1<= M < 2, 即M的形式为1.xxxx的形式,xxx表示小数位 IEEE 754规定,计算机内部保存M时,默认这个数的第一位总是1,因此可以舍去,只保存后面的xxx部分,如1.01,只保存01,读取的时候,再把第一位的1加上,这样做的目的是可以节省1位有效数字,52实际可存储53位。

在计算机内部,浮点数都是以二进制来表示的,所以十进制的浮点数要先转换为二进制浮点数,转换方式为:

3.png 重复该操作至64位小数点后第一位为0,然后将其升序排列,获取尾数,根据双精度标准,四舍五入到52位 得到0.1的二进制表示: 0.000110011001100110011001100110010011001100110011001101 * 2^0

科学计数法表示为: 1.10011001100110011001100110010011001100110011001101×2^(-4) 0.1的S,E,M值分别如下所示:

S = 0, E = -4, M = 10011001 10011001 10011001 10011001 10011001 10011001 1010

指数位E的真实值为1023+(-4)=1019,二进制表示为:0 1111 1110 11 M的二进制表示需52位,不足52后在右边用0补足

0.1在计算机中的二进制存储表示为: 4.png 同理可得0.2的二进制表达

S = 0, E = -3, M = 10011001 10011001 10011001 10011001 10011001 10011001 1010

指数位E的真实值为1023+(-3)= 1021,二进制表示为:0 1111 1111 01

5.png 由此可推算出0.1+0.2 = 0.300000000000000187 !== 0.3

第二种计算方式: 将0.1和0.2使用浮点数加法进行计算:

  1. 对齐阶码 截屏2021-12-18 下午7.34.44.png
  2. 尾数相加 截屏2021-12-18 下午7.35.37.png
  3. 计算过程

截屏2021-12-18 下午7.36.29.png 科学计数法:1.00110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 01111 * 2^(-2) M = 00110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 01111 M超过了52位,四舍五入, 01111 => 100 (二进制中的1舍去需要进位) M = 00110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 100(转为10进制为0.20000000000000018) S = 0, E = -2

  1. 最终结果 截屏2021-12-18 下午7.37.12.png

⚠️:任何一种进制数,如果想要补0而又不改变其大小的话,对于小数点左面的整数部分,就只能在最左边的最高有效数字(非0数字)前面补0,对于小数点右面的小数部分,则只能在最右边的最低有效数字后面补0

⚠️:IEEE 754 规定,浮点数被转成十进制数字字符串,当这个字符串(使用 Round to Even 向偶舍入)转回浮点数时,必须要跟原来的数相同。对双精度浮点数来说,十进制字符串使用17位有效数字即可保存原始二进制值


参考文献:www.ruanyifeng.com/blog/2010/0…

参考文献:objcer.com/2017/10/16/…

参考文献:betterprogramming.pub/why-is-0-1-…

参考文献:zhuanlan.zhihu.com/p/87672024

参考文献:zhuanlan.zhihu.com/p/351127362

参考文献:polarisxu.studygolang.com/posts/basic…