What's wrong with using == to compare floats in Java?

后端 未结 21 1937
你的背包
你的背包 2020-11-22 01:00

According to this java.sun page == is the equality comparison operator for floating point numbers in Java.

However, when I type this code:



        
相关标签:
21条回答
  • 2020-11-22 01:24

    The correct way would be

    java.lang.Float.compare(float1, float2)
    
    0 讨论(0)
  • 2020-11-22 01:26

    First of all, are they float or Float? If one of them is a Float, you should use the equals() method. Also, probably best to use the static Float.compare method.

    0 讨论(0)
  • 2020-11-22 01:27

    I think there is a lot of confusion around floats (and doubles), it is good to clear it up.

    1. There is nothing inherently wrong in using floats as IDs in standard-compliant JVM [*]. If you simply set the float ID to x, do nothing with it (i.e. no arithmetics) and later test for y == x, you'll be fine. Also there is nothing wrong in using them as keys in a HashMap. What you cannot do is assume equalities like x == (x - y) + y, etc. This being said, people usually use integer types as IDs, and you can observe that most people here are put off by this code, so for practical reasons, it is better to adhere to conventions. Note that there are as many different double values as there are long values, so you gain nothing by using double. Also, generating "next available ID" can be tricky with doubles and requires some knowledge of the floating-point arithmetic. Not worth the trouble.

    2. On the other hand, relying on numerical equality of the results of two mathematically equivalent computations is risky. This is because of the rounding errors and loss of precision when converting from decimal to binary representation. This has been discussed to death on SO.

    [*] When I said "standard-compliant JVM" I wanted to exclude certain brain-damaged JVM implementations. See this.

    0 讨论(0)
  • 2020-11-22 01:27

    you may want it to be ==, but 123.4444444444443 != 123.4444444444442

    0 讨论(0)
  • 2020-11-22 01:29

    the correct way to test floats for 'equality' is:

    if(Math.abs(sectionID - currentSectionID) < epsilon)
    

    where epsilon is a very small number like 0.00000001, depending on the desired precision.

    0 讨论(0)
  • 2020-11-22 01:29

    Just to give the reason behind what everyone else is saying.

    The binary representation of a float is kind of annoying.

    In binary, most programmers know the correlation between 1b=1d, 10b=2d, 100b=4d, 1000b=8d

    Well it works the other way too.

    .1b=.5d, .01b=.25d, .001b=.125, ...

    The problem is that there is no exact way to represent most decimal numbers like .1, .2, .3, etc. All you can do is approximate in binary. The system does a little fudge-rounding when the numbers print so that it displays .1 instead of .10000000000001 or .999999999999 (which are probably just as close to the stored representation as .1 is)

    Edit from comment: The reason this is a problem is our expectations. We fully expect 2/3 to be fudged at some point when we convert it to decimal, either .7 or .67 or .666667.. But we don't automatically expect .1 to be rounded in the same way as 2/3--and that's exactly what's happening.

    By the way, if you are curious the number it stores internally is a pure binary representation using a binary "Scientific Notation". So if you told it to store the decimal number 10.75d, it would store 1010b for the 10, and .11b for the decimal. So it would store .101011 then it saves a few bits at the end to say: Move the decimal point four places right.

    (Although technically it's no longer a decimal point, it's now a binary point, but that terminology wouldn't have made things more understandable for most people who would find this answer of any use.)

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