Why is comparing floats inconsistent in Java?

前端 未结 8 609
不思量自难忘°
不思量自难忘° 2020-11-30 23:16
class Test{  
    public static void main(String[] args){  
        float f1=3.2f;  
        float f2=6.5f;  

        if(f1==3.2){
            System.out.println(\"         


        
相关标签:
8条回答
  • 2020-11-30 23:55

    They're both implementations of different parts of the IEEE floating point standard. A float is 4 bytes wide, whereas a double is 8 bytes wide.

    As a rule of thumb, you should probably prefer to use double in most cases, and only use float when you have a good reason to. (An example of a good reason to use float as opposed to a double is "I know I don't need that much precision and I need to store a million of them in memory.") It's also worth mentioning that it's hard to prove you don't need double precision.

    Also, when comparing floating point values for equality, you'll typically want to use something like Math.abs(a-b) < EPSILON where a and b are the floating point values being compared and EPSILON is a small floating point value like 1e-5. The reason for this is that floating point values rarely encode the exact value they "should" -- rather, they usually encode a value very close -- so you have to "squint" when you determine if two values are the same.

    EDIT: Everyone should read the link @Kugathasan Abimaran posted below: What Every Computer Scientist Should Know About Floating-Point Arithmetic for more!

    0 讨论(0)
  • 2020-11-30 23:58

    Float has less precision than double, bcoz float is using 32bits inwhich 1 is used for Sign, 23 precision and 8 for Exponent . Where as double uses 64 bits in which 52 are used for precision, 11 for exponent and 1for Sign....Precision is important matter.A decimal number represented as float and double can be equal or unequal depends is need of precision( i.e range of numbers after decimal point can vary). Regards S. ZAKIR

    0 讨论(0)
  • 2020-11-30 23:59

    6.5 can be represented exactly in binary, whereas 3.2 can't. That's why the difference in precision doesn't matter for 6.5, so 6.5 == 6.5f.

    To quickly refresh how binary numbers work:

    100 -> 4
    
    10 -> 2
    
    1 -> 1
    
    0.1 -> 0.5 (or 1/2)
    
    0.01 -> 0.25 (or 1/4)
    

    etc.

    6.5 in binary: 110.1 (exact result, the rest of the digits are just zeroes)

    3.2 in binary: 11.001100110011001100110011001100110011001100110011001101... (here precision matters!)

    A float only has 24 bits precision (the rest is used for sign and exponent), so:

    3.2f in binary: 11.0011001100110011001100 (not equal to the double precision approximation)

    Basically it's the same as when you're writing 1/5 and 1/7 in decimal numbers:

    1/5 = 0,2
    1,7 = 0,14285714285714285714285714285714.
    
    0 讨论(0)
  • 2020-12-01 00:08
    class Test {  
      public static void main(String[] args) {  
        float f1=3.2f;  
        float f2=6.5f;  
    
        if(f1==3.2f)  
          System.out.println("same");  
        else  
          System.out.println("different");  
    
        if(f2==6.5f)  
          System.out.println("same");  
        else  
          System.out.println("different");  
        }  
      }
    

    Try like this and it will work. Without 'f' you are comparing a floating with other floating type and different precision which may cause unexpected result as in your case.

    0 讨论(0)
  • 2020-12-01 00:16

    To see what you're dealing with, you can use Float and Double's toHexString method:

    class Test {
        public static void main(String[] args) {
            System.out.println("3.2F is: "+Float.toHexString(3.2F));
            System.out.println("3.2  is: "+Double.toHexString(3.2));
            System.out.println("6.5F is: "+Float.toHexString(6.5F));
            System.out.println("6.5  is: "+Double.toHexString(6.5));
        }
    }
    $ java Test
    3.2F is: 0x1.99999ap1
    3.2  is: 0x1.999999999999ap1
    6.5F is: 0x1.ap2
    6.5  is: 0x1.ap2
    

    Generally, a number has an exact representation if it equals A * 2^B, where A and B are integers whose allowed values are set by the language specification (and double has more allowed values).

    In this case,
    6.5 = 13/2 = (1+10/16)*4 = (1+a/16)*2^2 == 0x1.ap2, while
    3.2 = 16/5 = ( 1 + 9/16 + 9/16^2 + 9/16^3 + . . . ) * 2^1 == 0x1.999. . . p1.
    But Java can only hold a finite number of digits, so it cuts the .999. . . off at some point. (You may remember from math that 0.999. . .=1. That's in base 10. In base 16, it would be 0.fff. . .=1.)

    0 讨论(0)
  • 2020-12-01 00:19

    The difference is that 6.5 can be represented exactly in both float and double, whereas 3.2 can't be represented exactly in either type. and the two closest approximations are different.

    An equality comparison between float and double first converts the float to a double and then compares the two. So the data loss.


    You shouldn't ever compare floats or doubles for equality; because you can't really guarantee that the number you assign to the float or double is exact.

    This rounding error is a characteristic feature of floating-point computation.

    Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits.

    In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation.

    Check What Every Computer Scientist Should Know About Floating-Point Arithmetic for more!

    0 讨论(0)
提交回复
热议问题