What's wrong with using == to compare floats i

2018-12-31 04:15发布

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

However, when I type this code:

if(sectionID == currentSectionID)

into my editor and run static analysis, I get: "JAVA0078 Floating point values compared with =="

What is wrong with using == to compare floating point values? What is the correct way to do it? 

21条回答
谁念西风独自凉
2楼-- · 2018-12-31 05:03

Floating point values can be off by a little bit, so they may not report as exactly equal. For example, setting a float to "6.1" and then printing it out again, you may get a reported value of something like "6.099999904632568359375". This is fundamental to the way floats work; therefore, you don't want to compare them using equality, but rather comparison within a range, that is, if the diff of the float to the number you want to compare it to is less than a certain absolute value.

This article on the Register gives a good overview of why this is the case; useful and interesting reading.

查看更多
泛滥B
3楼-- · 2018-12-31 05:06

Are you dealing with outsourced code that would use floats for things named sectionID and currentSectionID? Just curious.

@Bill K: "The binary representation of a float is kind of annoying." How so? How would you do it better? There are certain numbers that cannot be represented in any base properly, because they never end. Pi is a good example. You can only approximate it. If you have a better solution, contact Intel.

查看更多
只靠听说
4楼-- · 2018-12-31 05:07

One way to reduce rounding error is to use double rather than float. This won't make the problem go away, but it does reduce the amount of error in your program and float is almost never the best choice. IMHO.

查看更多
与风俱净
5楼-- · 2018-12-31 05:10

What is wrong with using == to compare floating point values?

Because it's not true that 0.1 + 0.2 == 0.3

查看更多
牵手、夕阳
6楼-- · 2018-12-31 05:12

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

查看更多
闭嘴吧你
7楼-- · 2018-12-31 05:14

This is a problem not specific to java. Using == to compare two floats/doubles/any decimal type number can potentially cause problems because of the way they are stored. A single-precision float (as per IEEE standard 754) has 32 bits, distributed as follows:

1 bit - Sign (0 = positive, 1 = negative)
8 bits - Exponent (a special (bias-127) representation of the x in 2^x)
23 bits - Mantisa. The actuall number that is stored.

The mantisa is what causes the problem. It's kinda like scientific notation, only the number in base 2 (binary) looks like 1.110011 x 2^5 or something similar. But in binary, the first 1 is always a 1 (except for the representation of 0)

Therefore, to save a bit of memory space (pun intended), IEEE deccided that the 1 should be assumed. For example, a mantisa of 1011 really is 1.1011.

This can cause some issues with comparison, esspecially with 0 since 0 cannot possibly be represented exactly in a float. This is the main reason the == is discouraged, in addition to the floating point math issues described by other answers.

Java has a unique problem in that the language is universal across many different platforms, each of which could have it's own unique float format. That makes it even more important to avoid ==.

The proper way to compare two floats (not-language specific mind you) for equality is as follows:

if(ABS(float1 - float2) < ACCEPTABLE_ERROR)
    //they are approximately equal

where ACCEPTABLE_ERROR is #defined or some other constant equal to 0.000000001 or whatever precision is required, as Victor mentioned already.

Some languages have this functionality or this constant built in, but generally this is a good habit to be in.

查看更多
登录 后发表回答