20
#include <stdbool.h>

bool Equality(double a, double b, double epsilon)
{
  if (fabs(a-b) < epsilon) return true;
  return false;
}

I tried this method to compare two doubles, but I always get problems since I don't know how to chose the epsilon, actually I want to compare small numbers (6 6 digits after the decimal point) like 0.000001. I tried with some numbers, sometimes I get 0.000001 != 0.000001 and sometimes 0.000001 == 0.000002 Is there another method else than comparing with the epsilon?

My purpose is to compare two doubles (which represent the time in my case). The variable t which represents the time in milliseconds is a double. It is incremented by another function 0.000001 then 0.000002 etc. each time t changes, I want to check if it is equal to another variable of type double tt, in case tt == t, I have some instructions to execute..
Thanks for your help

Shweta
  • 5,198
  • 11
  • 44
  • 58
kate
  • 201
  • 1
  • 2
  • 4
  • "Epsilon", not epselon. http://en.wikipedia.org/wiki/Epsilon – Roddy May 13 '11 at 08:36
  • 1
    Neither 0.000001 nor 0.000002 have an exact representation as floating point, both are infinite binary fractions with recurring decimals. Additionally, fabs(a-b) is prone to catastrophic cancellation. – Gunther Piez May 13 '11 at 08:48
  • If you don't know what this is all about, you can avoid at least the first problem by using an epsilon, which can be exactly represented as float, like 0.00000095367431640625, which is 2^-20 and close to the 10^-6 you want – Gunther Piez May 13 '11 at 08:53
  • 1
    Why are you using `float` in the first place? Prefer `double` without a **very strong** for other floating-point types. Of course your issue still remains whether it's `float`s or `double`s. – pmg May 13 '11 at 09:05
  • Actually it was a mistake. I am using doubles. my purpose is to compare two doubles (which represent the time in my case). The variable t which represents the time in milliseconds is a double. It is incremented by another function 0.000001 then 0.000002 etc. each time t changes, I want to check if it is equal to another variable of type double tt, in case tt == t, I have some instructions to execute.. – kate May 13 '11 at 09:26
  • To choose epsilon you can see: Knuth, Donald E. (1998). The Art of Computer Programming. Volume 2: Seminumerical Algorithms. Third edition. Section 4.2.2, p. 233. Reading, MA: Addison-Wesley. ISBN 0-201-89684-2. For a C implementation see http://fcmp.sourceforge.net/ and in particular the README file. – Alessandro Jacopson Jun 27 '12 at 12:41
  • 1
    possible duplicate of [Most effective way for float and double comparison](http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison) – Roddy Jun 26 '13 at 10:32

4 Answers4

23

Look here: http://floating-point-gui.de/errors/comparison/

Due to rounding errors, most floating-point numbers end up being slightly imprecise. As long as this imprecision stays small, it can usually be ignored. However, it also means that numbers expected to be equal (e.g. when calculating the same result through different correct methods) often differ slightly, and a simple equality test fails.

And, of course, What Every Computer Scientist Should Know About Floating-Point Arithmetic

Chris Happy
  • 7,088
  • 2
  • 22
  • 49
Roddy
  • 66,617
  • 42
  • 165
  • 277
3

First: there's no point in computing a boolean value (with the < operator) and then wrapping that in another boolean. Just write it like this:

bool Equality(float a, float b, float epsilon)
{
  return fabs(a - b) < epsilon;
}

Second, it's possible that your epsilon itself isn't well-represented as a float, and thus doesn't look like what you expect. Try with a negative power of 2, such as 1/1048576 for instance.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • Thanks for your reply. when eps = 0.000001, I get a wrong result (0.000001 == 0.000002), however when I use something like 1/1048576, the result is always != (even if I compare 0.000001 to 0.000001) :( – kate May 13 '11 at 08:52
1

Alternatively, you could compare two integers instead. Just multiply your two floats by the desired precision and cast them to integers. Be sure to round up/down correctly. Here is what it looks like:

BOOL floatcmp(float float1, float float2, unsigned int precision){
   int int1, int2;

   if (float1 > 0)
      int1 = (int)(float1 * precision + .5);
   else
      int1 = (int)(float1 * precision - .5);

   if (float2 > 0)
      int2 = (int)(float2 * precision + .5);
   else
      int2 = (int)(float2 * precision - .5);

   return (int1 == int2);
}
rebs01
  • 11
  • 1
1

Keep in mind that when float a = +2^(254-127) * 1.___22 zeros___1 and float b = +2^(254-127) * 1.___23 zeros___ then we expect abs(a-b) < epsilon but instead a - b = +2^(254-127-23) * 1.___23 zeros___ = 20282409603651670423947251286000 which is much bigger than epsilon...

Chameleon
  • 1,804
  • 2
  • 15
  • 21