Skip to content
更新时间: 2024-02-24

为什么0.1+0.2==0.3是false?为什么0.1+0.1==0.2是true?

简单来说就是,0.1和0.2的二进制是一个无限循环小数,而存储的时候不可能完整的存储,肯定会丢失精度。
至于为什么0.1+0.1等于0.2,我只能说算是巧合。

详细一点点来解释:
在数学上这肯定是true,所以说就涉及到js(其实不止js语言)底层是怎么保存0.1和0.2这个数字了。
回想一下在现实中你也没办法把 0.111111111...这个循环完整写出来,你只能写下1/9或者0.1˙,也就是说换一种表达形式。
而计算机中目前没有别的表达形式,除非用字符串来表达,但是字符串非常地慢!

这样想,如果底层是用字符串保存(也就是"0.1")那计算肯定是正确的。
但是用字符串来保存,那计算就是个大问题了,也就是计算"0.1"+"0.2"这个表达式在硬件(cpu)上面是没有提供的。
要做这个计算就只能在软件层(代码)实现,但是这样对于浮点数计算来说,速度是非常地慢,内存占用也高。
所以一般都不可能采用这种高精度的计算方式(不管什么语言都是),最终采用了IEEE-754双精度浮点数。

二进制的小数是怎么样的?

在没有小数的时候我相信很多人都懂,二进制的1010(2)=123+022+121+020
所以我们可以按照这个规律来想,
0.1=210.01=220.001=230.0001=24...

按照上面这样二进制的小数就是0.1011100...这样的形式了,满足0和1组成。
那十进制的0.1转成二进制就是
0.1(10)=0.0001100110011001100110011001100110011001100110011001100...(2)

二进制小数是怎么进位的?

很简单,只要是1就进位,下面举例
保留两位:0.1001 => 0.10
保留三位:0.1001 => 0.101、0.1011 => 0.110

IEEE-754双精度浮点数的格式是怎么样的?

一个有64个bit,0-51是小数部分共52位,52-62是指数部分共11位,63是标记位0表示正数1表示负数。
还有就是需要用科学计数法调整数字,也就是要改成1.xxxxxxxxx2n的形式,比如
0.00011001100110011001100... = 1.1001100110011001100... * 24

  • 首先因为是整数,所以符号位是0
  • 然后整数部分的1是不存的,毕竟要求使用科学计数法,而二进制又只有0和1,那么默认所有IEEE-754的数都是有一个1开头的整数。
  • 其次,不是直接将-4这个指数转成二进制保存到指数部分的,而是将e = n + 1023,计算之后得到的e转为二进制保存的,也就是1019(10)=01111111011(2)
  • 最后,从小数部位取出53位,然后进变成52位。
  • 最终0.1的IEEE-754就是,
    0 01111111011 1001100110011001100110011001100110011001100110011010