V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dawang
V2EX  ›  PHP

有关 PHP 和 js 浮点运算的坑

  •  
  •   dawang · 2017-10-11 15:07:40 +08:00 · 1625 次点击
    这是一个创建于 2361 天前的主题,其中的信息可能已经有所发展或是发生改变。

    javascript

    0.1 + 0.2 为啥不等于 0.3 ? (正确结果:0.30000000000000004 )

    0.8 * 7 为啥不等于 5.6 ? (正确结果:5.6000000000000005 )

    PHP

    var_dump(intval(0.58 * 100));

    正确结果是 57,而不是 58

    浮点运算惹的祸

    其实这些结果都并非语言的 bug,但和语言的实现原理有关,js 所有数字统一为 Number, 包括整形实际上全都是双精度( double )类型。

    而 PHP 会区分 int 还是 float。不管什么语言,只要涉及浮点运算,都是存在类似的问题,使用时一定要注意。

    浮点二进制原理

    根据国际标准 IEEE 754,任意一个二进制浮点数 V 可以表示成下面的形式:

    V = (-1)s * M * E 
    
        1. (-1)s 表示符号位,当 s=0,V 为正数;当 s=1,V 为负数。
        2. M 表示有效数字,大于等于 1,小于 2。
        3. 2E 表示指数位。
    

    举例来说:十进制的-5.0,写成二进制是-101.0,相当于-1.01×22。那么,s=1,M=1.01 ,E=2。 IEEE 754 规定,对于 32 位的浮点数,最高的 1 位是符号位 s,接着的 8 位是指数 E,剩下的 23 位为有效数字 M。

    对于 64 位的浮点数,最高的 1 位是符号位 S,接着的 11 位是指数 E,剩下的 52 位为有效数字 M。

    IEEE 754 对有效数字 M 和指数 E,还有一些特别规定。

    前面说过,1≤M<2,也就是说,M 可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。IEEE 754 规定,在计算机 内部保存 M 时,默认这个数的第一位总是 1,因此可以被舍去,只保存后面的 xxxxxx 部分。比如保存 1.01 的时候,只 保存 01,等到读取的时候,再把第一位的 1 加上去。这样做的目的,是节省 1 位有效数字。以 32 位浮点数为例,留给 M 只有 23 位,将第一位的 1 舍去以后,等于可以保存 24 位有效数字。

    至于指数 E,情况就比较复杂。

    首先,E 为一个无符号整数( unsigned int )。这意味着,如果 E 为 8 位,它的取值范围为 0~255 ;如果 E 为 11 位,它 的取值范围为 0~2047。但是,我们知道,科学计数法中的 E 是可以出现负数的,所以 IEEE 754 规定,E 的真实值必须 由 E 再减去一个中间数,对于 8 位的 E,这个中间数是 127 ;对于 11 位的 E,这个中间数是 1023。 比如,210 的 E 是 10,所以保存成 32 位浮点数时,必须保存成 10(E 的真实值)+127=137(E),即 10001001。

    然后,指数 E 还可以再分成三种情况: ( 1 ) E 不全为 0 或不全为 1。这时,浮点数就采用上面的规则表示,即指数 E 的计算值减去 127 (或 1023 ),得到真实 值,再将有效数字 M 前加上第一位的 1。 ( 2 ) E 全为 0。这时,浮点数的指数 E 等于 1-127 (或者 1-1023 ),有效数字 M 不再加上第一位的 1,而是还原为 0.xxxxxx 的小数。这样做是为了表示±0,以及接近于 0 的很小的数字。 ( 3 ) E 全为 1。这时,如果有效数字 M 全为 0,表示±无穷大(正负取决于符号位 s );如果有效数字 M 不全为 0,表示 这个数不是一个数( NaN )。>

    参考

    http://www.laruence.com/2013/03/26/2884.html
    http://www.cnblogs.com/qlwy/archive/2012/08/17/2644470.html

    原文: http://www.yinqisen.cn/blog-782.html

    azh7138m
        1
    azh7138m  
       2017-10-11 15:34:53 +08:00 via Android
    浮点数就是这样啊,C/C++同样
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2830 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 14:33 · PVG 22:33 · LAX 07:33 · JFK 10:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.