4

Possible Duplicate:
How should I do floating point comparison?

Is it not recommended to compare for equality a double and a double literal in C++, because I guess it is compiler dependent?

To be more precise it is not OK to compare a double which is hard-coded (a literal in the source code) and a double which should be computed, as the last number of the resultant of the calculation can vary from one compiler to another. Is this not standardized?

I heard this is mentioned in Knuth's TeXbook, is that right?

If this is all true, what is the solution?

Community
  • 1
  • 1
Narek
  • 38,779
  • 79
  • 233
  • 389

4 Answers4

6

You've misunderstood the advice a bit. The point is that floating-point computations aren't exact. Rounding errors occur, and precision is gradually lost. Take something as simple as 1.0/10.0. The result should be 0.1, but it isn't, because 0.1 cannot be represented exactly in floating-point format. So the actual result will be slightly different. The same is true for countless other operations, so the point has nothing to do with const doubles. It has to do with not expecting the result to be exact. If you perform some computation where the result should be 1.0, then you should not test it for equality against 1.0, because rounding errors might mean that it actually came out 0.9999999997 instead.

So the usual solution is to test if the result is sufficiently close to 1.0. If it is close, then we assume "it's good enough", and act as if the result had been 1.0.

The bottom line is that strict equality is rarely used for floating-point values. Instead, you should test if the difference between the two values is less than some small value (typically called the epsilon)

jalf
  • 243,077
  • 51
  • 345
  • 550
  • 1
    +1 for the vague *sufficiently close* instead of the misleading "just test for a certain absolute error". – R. Martinho Fernandes May 17 '11 at 08:51
  • Here arise two questions: Does compiler need to be standardized for rounding a number. And what is the problem to store 0.1 in memory as double in c++ stores? – Narek May 17 '11 at 08:53
  • @Narek: 0.1 in binary is an infinite expansion, kinda like how you can't represent 1/3 in base 10. – R. Martinho Fernandes May 17 '11 at 08:58
  • @Narek: the second part is fairly simple to understand. Not all fractions can be expressed in every number base. For example, in base 10, you can't express `1/3` exactly. You have to round off at some point, and lose precision (0.333333...). Similarly, in base 2, (which is used by float and double) you can't express `1/10` exactly. – jalf May 17 '11 at 08:58
  • I'm not exactly sure what you mean with the first part. – jalf May 17 '11 at 08:58
1

The problem you are talking about is due to rounding errors and will happen for every floating point number. What you can do is define an epsilon and see if the difference between the two floating point numbers is smaller than this. E.g.:

double A = somethingA();
double B = somethingB();

double epsilon = 0.00001;

if (abs(A - B) < epsilon)
  doublesAreEqual();

[Edit] Also see this question: What is the most effective way for float and double comparison?.

Community
  • 1
  • 1
AVH
  • 11,349
  • 4
  • 34
  • 43
  • 1
    Just don't go around blindly solving your problem with this, ok? – R. Martinho Fernandes May 17 '11 at 08:46
  • Note that standard library comes with `std::numeric_limits::epsilon()` to determine the smallest possible difference to 1.0 that can be represented for type T; Don't use this for the above check (as the epsilon will _not_ be representable for higher exponents), just for reference – sehe May 17 '11 at 08:47
  • @Martinho: that makes us all very curious of your answer? If you wanted to warn about using a 'arbitrary' fixed epsilon, why don't you state that, so your comment will be helpful – sehe May 17 '11 at 08:48
  • @sehe: Martinho didn't write an answer... – Lightness Races in Orbit May 17 '11 at 08:53
  • 1
    @sehe: In short: because the solution depends on the exact problem. This is just a solution to *a subset* of problems arising from the nature of FP. I like [this answer](http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison/77735#77735). – R. Martinho Fernandes May 17 '11 at 09:01
  • @Martinho: thanks; that was indeed even more helpful than I expected – sehe May 17 '11 at 09:21
  • @sehe: I think it's pretty clear that he's afraid the OP will throw this exact code at the problem, not stopping to think carefully about the situation and about how he can apply the _mindset_, not the _code example_, to his program and to programs he writes in the future. Having had to explain floating-point inaccuracy to people many times in the past, I certainly share his sentiment. – Lightness Races in Orbit May 17 '11 at 09:25
  • I think link is worth more than the flat warning. I should start using the FAQ index page more often, so I can just add said link myself – sehe May 17 '11 at 09:27
0

The key problem is how floating point arithmetic works - it includes rounding that can lead to comparison for equality evaluated wrong. This applies to all floating point numbers regardless of whether variable is declared const or not.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
0

if you do floating point calculations and you need to do comparisons with certain fixed values it is always safer to use an epsilon value to take into account precision errors .

Example:

double calcSomeStuf();

if ( calcSomeStuf() == 0.1 ) { ...}

is a bad idea

however:

const double epsilon = 0.005

double calcSomeStuf();

if ( abs(calcSomeStuf() - 0.1) < epsilon ) { ...}

is a lot safer (especially considering the fact that 0.1 cannot be represented exactly as a double)

This is necessary because when accumulating floating point operations rounding errors occur, and due to the nature of floating point not all numbers can be represented exactly

Joris Mans
  • 6,024
  • 6
  • 42
  • 69