2

I think the precision of double is causing that problem, as it was described in similiar posts, but I would like to know if there is a way to achieve correct result. I'm using function template which compares two parameters and returns true if they are equal.

template <class T>
bool eq(T one, T two)
{
  if (one == two)
    return true;
  else
    return false;
}

It works with eq (0.8,0.8), but it doesn't work with eq (0.8*0.2,0.16). As I mentioned I assume it has to do with double precision as it also works fine with int eq(8*2,16).

3
  • You're probably right. One way to check would be to print them both out and see if there is a slight difference. Commented Jan 6, 2010 at 21:34
  • 8
    You can simplify the if/else logic by simply writing: return (one == two); Commented Jan 6, 2010 at 21:35
  • @Matrix: since you don't need parentheses for return, that "simplifies" to return one == two;. Commented Jan 7, 2010 at 3:10

6 Answers 6

18

First you should read one (or both) of these articles: What Every Computer Scientist Should Know About Floating-Point Arithmetic and The Perils of Floating Point.

If you are looking for a solution for your template, I would suggest using template specialization for the cases where T==double and T==float.

Sign up to request clarification or add additional context in comments.

Comments

5

You should rarely try to compare doubles for equality. Instead you need to decide on a margin of error that you are willing to accept:

return fabs(one - two) <= 0.000001

1 Comment

The standard library includes std::numeric_limits<T>::epsilon() ( stdcxx.apache.org/doc/stdlibref/numeric-limits.html#idx1014 ) to help you pick the margin of error.
3

You will want to overload your function and then do a comparison that is appropriate for floating point:

bool eq(double one, double two)
{
    // You'll want to choose a delta that is appropriate for your usage
    return fabs(one - two) < DELTA;
}

You'll also want to do another overload for float's.

5 Comments

A fixed delta in a template like this will rarely by useful, as the appropriate value will depend on context. With floating point, equal is rarely meaningful - you should generally think close_enough().
The standard library includes std::numeric_limits<T>::epsilon() ( stdcxx.apache.org/doc/stdlibref/numeric-limits.html#idx1014 ) to help you pick the margin of error.
There is no reason for that template <> in there.
@avakar - yes there is a reason. That make it a specialization of the template rather then an overloaded function. While this case may be simple enough that the overload rules will work fine, in general I prefer to avoid the complexity of mixing templates and free functions.
You should prefer overloads to specializations: gotw.ca/publications/mill17.htm.
2

Here is another article about the problems with comparing floating point numbers.

Comparing for equality

Floating point math is not exact. Simple values like 0.2 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. Different compilers and CPU architectures store temporary results at different precisions, so results will differ depending on the details of your environment. If you do a calculation and then compare the results against some expected value it is highly unlikely that you will get exactly the result you intended.

Comments

1

You should never compare floating point without specifying precision.

This will return false:

cout << (0.8 * 2 < 0.16 ? true : false) << endl;

But this will return true:

cout << ((0.8 * 2 - 0.16) < 0.001 ? true : false) << endl;

Comments

0

You always will be able to use rounding functions to be sure.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.