views:

199

answers:

5

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

+5  A: 

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
Mark Byers
The standard library includes std::numeric_limits<T>::epsilon() ( http://stdcxx.apache.org/doc/stdlibref/numeric-limits.html#idx1014 ) to help you pick the margin of error.
Max Lybbert
+15  A: 

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.

Doc Brown
A: 

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

Drewen
+3  A: 

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.

R Samuel Klatchko
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().
Stephen C. Steel
It works now. Thanks
Kary
The standard library includes std::numeric_limits<T>::epsilon() ( http://stdcxx.apache.org/doc/stdlibref/numeric-limits.html#idx1014 ) to help you pick the margin of error.
Max Lybbert
There is no reason for that `template <>` in there.
avakar
@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.
R Samuel Klatchko
You should prefer overloads to specializations: http://www.gotw.ca/publications/mill17.htm.
avakar
@avakar - thanks for that guru-of-the-week article.
R Samuel Klatchko
+2  A: 

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.

epatel