Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

0.1+0.2!=0.3,浮点数你的节操何在!?

  在JavaScript中0.1+0.2是不会等于0.3的。如果你用学过C语言就一定会知道浮点数的精度问题。CPU做计算的时候处理的是二进制的值,而有些十进制的小数写成二进制之后就变成了无限循环小数,当再次转换成十进制的时候由于保留了有效位,精度就会因此损失。这样就可以解释为什么0.1+0.2!=0.3了,但是我们应该更深入的了解为什么0.2+0.3可以等于0.5呢?JavaScript用的是IEEE754浮点数标准。我们先来说说IEEE754浮点数在内存中的储存方式。以32位浮点数为例:
    符号位:最左边第1位
    指数位:第2位到第9位
    尾数位:剩下的23位
  大家应该都知道科学计数法吧,比如10000可以写作 1×104 这就是我们在十进制中使用的科学计数法,你可以看作是小数点的偏移。在IEEE754中同样使用科学计数法,但是是底数为2的科学计数法,如果把数字写成二进制的,同样可以看作是小数点的偏移。
  现在,我们要把0.1这个数字写成IEEE754的表达法。首先,把它转换成二进制。这个用乘二取整法口算就可以了0.1D=0.000110011(0011)B,然后我们移动小数点的位置,得到1.10011001100110011001100B这个就是尾数部分,但是还没完,因为位数是23位的超出23位的部分会被近似也就是零舍一入。所以,由于这个数字的第24位是1,所以经过零舍一入,这个数字的位数部分在内存中最终会变成10011001100110011001101(由于整数部分永远是1,IEEE754规定它不用保存)。下面是计算指数,由于小数点向左移动了4位,指数部分就应该是-4了,这是科学计数法的性质。最后,因为它是正数,符号部分为正。我们可以用同样的方法计算出0.2和0.3。这里,我们说的是32位的IEEE754浮点数,而事实上JavaScript中使用的是64位的IEEE754浮点数,在64位中:
    符号位:最左边第1位
    指数位:第2位到第12位
    尾数位:剩下的52位
  现在,我们就来计算0.1+0.2,首先,把他们用IEEE754的方法表示出来,方法和32位的类似。
十进制数 指数 二进制尾数
0.1 -4 1.1001100110011001100110011001100110011001100110011010
0.2 -3 1.1001100110011001100110011001100110011001100110011010
0.3 -2 1.0011001100110011001100110011001100110011001100110011
  由于它们的指数不同,所以我们要把它的指数统一,也就是把小的指数变大。现在,我们把0.1的指数-4变成0.2的指数-3,由于指数变化了,小数点的位置也要跟着变化。这样就变成了。
    0.1100110011001100110011001100110011001100110011001101
  + 1.1001100110011001100110011001100110011001100110011010
  =10.0110011001100110011001100110011001100110011001100111
  这个结果还可以移动一次小数点。变成
    1.00110011001100110011001100110011001100110011001100111
  由于位数位超出了52位,那么第53位就进行零舍一入,得到下面的最终结果
    1.0011001100110011001100110011001100110011001100110100
  小数点移动了,指数也要由原来的-3变成了-2。这个就是计算后得到的0.3,和上面表格中的0.3相比,最后的几位因为经过两次的近似计算所以和真正的0.3有出入。这就是造成0.1+0.2!=0.3的原因!
网名:
54.224.247.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^