开发者

Why is this true?

This is IEEE 754 standard question. I don't completely understand the mechanics behind it.

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


Because a float can only hold about 7 to 8 significant digits. That is, it doesn't have enough bits to represent the number 2000000050 exactly, so it gets rounded to 2000000000.

Specifically speaking, a float consists of three parts:

  • the sign bit (1 bit)
  • the exponent (8 bits)
  • the significand (24 bits, but only 23 bits are stored since the MSB of the significand is always 1)

You can think of floating point as the computer's way doing scientific notation, but in binary.

The precision is equal to log(2 ^ number of significand bits). That means a float can hold log(2 ^ 24) = 7.225 significant digits.

The number 2,000,000,050 has 9 significant digits. The calculation above tells us that a 24-bit significand can't hold that many significant digits. The reason why 2,000,000,000 works because there's only 1 significant digit, so it fits in the significand.

To solve the problem, you would use a double since it has a 52-bit significand, which is more than enough to represent every possible 32-bit number.


Plainly said - 50 is a rounding error when a float has a value of two-billion.


You might find this trick to find the next representable value interesting.

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);

prints

The next float value after 2000000000 is 2000000128
The next double value after 2000000000.0000000 is 2000000000.0000002


It might help you understand the situation if you consider a program (C++) as below. It displays the groups of successive integers that get rounded to the same float value:

#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;                                                            
        }                                                                       
    }                                                                           
}

Output:

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

This indicates that floating point is only precise enough to represent all integers from 1999999850 to 1999999935, wrongly recording their value as 1999999872. So on for other values. This is the tangible consequence of the limited storage space mentioned above.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜