为什么这是真的?

时间:2010-11-04 05:29:01

标签: java c++ floating-point

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

public class Gray {  
    public static void main(String[] args){
        System.out.println( (float) (2000000000) == (float) (2000000000 + 50));
    }
}

4 个答案:

答案 0 :(得分:29)

因为float只能容纳大约7到8位有效数字。也就是说,它没有足够的位来准确表示数字2000000050,因此它被舍入到2000000000。

具体而言,float由三部分组成:

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

您可以将浮点视为计算机进行科学记数法的方式,而不是二进制。

精度等于log(2 ^ number of significand bits)。这意味着float可以保留log(2 ^ 24) = 7.225个有效数字。

数字2,000,000,050有9位有效数字。上面的计算告诉我们24位有效数字不能保存那么多有效数字。之所以2,000,000,000是有效的,因为只有1个有效数字,所以它适用于有效数字。

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

答案 1 :(得分:3)

简单地说 - 当浮点值为20亿时,50是舍入误差。

答案 2 :(得分:3)

你可能会发现这个技巧可以找到下一个有意义的值。

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

答案 3 :(得分:2)

如果你考虑下面的程序(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到1999999935之间的所有整数,错误地将它们的值记录为1999999872.因此,对于其他值。这是上述有限存储空间的实际结果。