0.1 + 0.2 !== 0.3是如何计算的

相关概念:

(1)64位双精度存储,计算机存储数据的类型之一,该存储类型的一个存储单元包括符号位,指数域,尾数域。

(2)符号位,对双精度来说位于第64位,占1个比特,代表数据是的正负,位于存储单元的最高为。

(3)指数位,对双精度来说位于第63位到第53位,占11个比特,代表尾数的指数部分的二进制。另外为了便于比较,该区域存储的均为非负值,将指数的实际值(-1023~1024)加上1023,所以得出存储值的范围是0~2047。

(4)尾数位,对双精度来说位于第52位到第1位,将小数转化为二进制后,通过添加指数位使小数位转化位1.****,其中正数1不占据尾数位,作为一个默认值,所以实际尾数位只是*******...*****(共52位)

0.1转化为二进制:

0.1 * 2 = 0.2

0.2 * 2 = 0.4

0.4 * 2 = 0.8

0.8 * 2 = 1.6

0.6 * 2 = 1.2

0.2 * 2 = 0.4

...

所以0.1的二进制小数位 0.00011001100...(1100循环),就是1.10011001100...(1100循环) * 2^-4,所以得出此时的存储单元为0(符号位)01111111011(指数位)1001100110011001100110011001100110011001100110011010(小数位最后一位是0舍1入得来的)。

0.2转化位二进制:

0.2 * 2 = 0.4

0.4 * 2 = 0.8

0.8 * 2 = 1.6

0.6 * 2 = 1.2

0.2 * 2 = 0.4

....

所以0.2的二进制小数位0.00110011...(1100循环),就是1.10011001100...(1100循环) * 2^-3,所以得出此时的存储单元为0(符号位)01111111100(指数位)1001100110011001100110011001100110011001100110011010(小数位最后一位是0舍1入得来的)。

此时两个数的存储已经可视化了,接下来是运算+,首先需要将指数位转化位一样,规则是小转大,所以小数位也会跟着变化。

0.1 -> 0.11001100...(1100循环) * 2^-3(第一个1是之前隐藏的整数位),开始运算。

0.1 + 0.2 =

0.11001100110011001100110011001100110011001100110011010(最后一位0超出舍弃)

+

1.1001100110011001100110011001100110011001100110011010

= 10.0110011001100110011001100110011001100110011001100111

将整数位10格式化位尾数位。

小数点左移一位:1.00110011001100110011001100110011001100110011001100111

去掉溢出的最后一位:1.0011001100110011001100110011001100110011001100110100(最后一位1,0舍1入得到此值)

左移后指数域+1:01111111101

最终结果:0(符号位)01110010111(指数位)0011001100110011001100110011001100110011001100110100(尾数位) = 0.30000000000000004

另一种方法,把小数换成二进制直接运算

0.1 -> 0.000110011001100110011001100110011001100110011001100110011

第一个1后只能有52位所以0舍1入后

0.1 -> 0.00011001100110011001100110011001100110011001100110011010

+

0.2 -> 0.0011001100110011001100110011001100110011001100110011001

= 0.010011001100110011001100110011001100110011001100110100(0舍1入)

注:0舍1入都是为了使数据在小数位上只有52位。

你可能感兴趣的:(javascript)