代码之家  ›  专栏  ›  技术社区  ›  fabmilo

为什么是这样?

  •  10
  • fabmilo  · 技术社区  · 14 年前

    这是IEEE 754标准问题。我不完全理解它背后的机制。

    public class Gray {  
        public static void main(String[] args){
            System.out.println( (float) (2000000000) == (float) (2000000000 + 50));
        }
    }
    
    4 回复  |  直到 13 年前
        1
  •  29
  •   In silico    14 年前

    因为A float 只能容纳大约7到8个有效数字。也就是说,它没有足够的位来精确地表示数字200000000050,所以它被四舍五入到2000000000。

    具体来说,a 浮动 由三部分组成:

    • 符号位(1位)
    • 指数(8位)
    • 有效位(24位,但由于有效位的最高有效位始终为1,因此只存储23位)

    你可以把浮点看成是计算机做科学记数法的方式,但它是二进制的。

    这个 精度 等于 log(2 ^ number of significand bits) . 这意味着 浮动 可容纳 log(2 ^ 24) = 7.225 有效数字。

    数字2000000050有9个有效数字。上面的计算告诉我们,24位有效位不能容纳那么多有效位。2000000000之所以有效,是因为只有一个有效数字,所以它符合有效数字。

    为了解决这个问题,您将使用 double 因为它有一个52位的有效位,这足以表示每一个可能的32位数字。

        2
  •  3
  •   Stevko    14 年前

    很明显-50是一个舍入误差,当一个浮点值为20亿。

        3
  •  3
  •   Peter Lawrey    14 年前

    您可能会发现这个技巧,以发现下一个可表示的价值有趣。

    float f = 2000000000;
    int binaryValue = Float.floatToRawIntBits(f);
    int nextBinaryValue = binaryValue+1;
    float nextFloat = Float.intBitsToFloat(nextBinaryValue);
    System.out.printf("The next float value after %.0f is %.0f%n",  f, nextFloat);
    
    double d = 2000000000;
    long binaryValue2 = Double.doubleToRawLongBits(d);
    long nextBinaryValue2 = binaryValue2+1;
    double nextDouble = Double.longBitsToDouble(nextBinaryValue2);
    System.out.printf("The next double value after %.7f is %.7f%n",  d, nextDouble);
    

    印刷品

    The next float value after 2000000000 is 2000000128
    The next double value after 2000000000.0000000 is 2000000000.0000002
    
        4
  •  2
  •   Tony Delroy    14 年前

    如果你考虑一个程序(C++),它可能会帮助你理解这种情况。它显示被四舍五入为相同浮点值的连续整数组:

    #include <iostream>                                                             
    #include <iomanip>                                                              
    
    int main()                                                                      
    {                                                                               
        float prev = 0;                                                             
        int count = 0;                                                              
        double from;                                                                
        for (double to = 2000000000 - 150; count < 10; to += 1.0)                   
        {                                                                           
            float now = to;                                                         
            if (now != prev)                                                        
            {                                                                       
                if (count)                                                          
                    std::cout << std::setprecision(20) << from << ".." << to - 1 << " ==> " << prev << '\n';                                                        
                prev = now;                                                         
                from = to;                                                          
                ++count;                                                            
            }                                                                       
        }                                                                           
    }
    

    输出:

    1999999850..1999999935 ==> 1999999872
    1999999936..2000000064 ==> 2000000000
    2000000065..2000000191 ==> 2000000128
    2000000192..2000000320 ==> 2000000256
    2000000321..2000000447 ==> 2000000384
    2000000448..2000000576 ==> 2000000512
    2000000577..2000000703 ==> 2000000640
    2000000704..2000000832 ==> 2000000768
    2000000833..2000000959 ==> 2000000896
    

    这表示浮点的精度仅足以表示1999999850到199999999935之间的所有整数,错误地将其值记录为19999999872。其他值也是如此。这是上述有限存储空间的有形后果。