Re: comparing doubles for equality



Logan Shaw wrote:
Richard Weeks wrote:
After some hair pulling over the issue of comparing doubles for equality, I came up with this solution based on the notion of relative difference. I'd appreciate your comments.

There is nothing wrong with comparing doubles to see if they are close
to each other, but it is not the same thing as comparing whether they
are equal. It would be less confusing if you called it something other
than equality.

Also, of course, be aware that round-off error is the real problem, and
for this approach to work right, you have to have some way of ensuring
that your computations don't accumulate more round-off error than your
margin allows for. That is not necessarily an easy problem.

#define MAXRELDIFF .000000000001

/* compare doubles for equality. First compare
integer parts; if they are unequal, return
false. If they are equal, calculate relative
difference of fractional parts and compare
it to a tolerance. */
int dbl_isequal(double a, double b)
{
double fraca, fracb, reldiff;
if((int)a == (int)b)
{
fraca = a - (int)a;
fracb = b - (int)b;
reldiff = rel_diff(fraca, fracb);
if(reldiff > MAXRELDIFF) return 0;
else return 1;
}
return 0;
}

I don't see why it's useful to compare only the fractional parts. These
are floating point types, so the fractional part will have different
precision depending on the integer part! In fact, for really large
numbers, the loss of precision could easily go into the integer part
of the number.

It seems like, if anything, you want the tolerance to be relative to
the magnitude of the numbers. That's what the round-off error is
relative to (for simple types of computations).

Therefore, it seems like this would be an improvement:


#define TOLERANCE 0.000000001

int dbl_isequal(double a, double b)
{
if (a < b * (1 - TOLERANCE)) return 0;
if (a > b * (1 + TOLERANCE)) return 0;
return 1;
}

Or something that has a little more symmetry:

#defined TOLERANCE 0.000000001

int dbl_isequal(doube a, double b)
{
if (a < b * (1 - TOLERANCE)) return 0;
if (b < a * (1 - TOLERANCE)) return 0;
return 1;
}


Here's how I do it (more or less):

#define TOLERANCE 0.0000001

int dbl_isequal(double a, double b)
{
return (fabs(a - b) < TOLERANCE) ? 1 : 0;
}

Works for me.

Bjørn
.



Relevant Pages

  • Re: comparing doubles for equality
    ... equality, I came up with this solution based on the notion of relative ... There is nothing wrong with comparing doubles to see if they are close ... /* compare doubles for equality. ... It seems like, if anything, you want the tolerance to be relative to ...
    (comp.programming)
  • Re: How do I make a string comparison switch?
    ... It tests for equality of hash compare. ... On average the string you are after is half way down the list, ... If it is a dense int, then the JVM does a tableswitch instruction to ...
    (comp.lang.java.help)
  • Re: string-question
    ... You can compare strings using compareTo, which returns an int. ... value of 0 indicates equality. ...
    (comp.lang.java.programmer)
  • Re: comparing doubles for equality
    ... #define TOLERANCE 0.0000001 ... int dbl_isequal ... your version accepts huge absolute differences because the numbers compared are astronomical. ... If it is OP, I don't see any guarantee that casting the double with int would work, when comparing say 38,000 to 3. ...
    (comp.programming)
  • Fuzzy comparison
    ... I'm trying to come up with a simple function that will allow me to compare ... long as they are within some tolerance but I also want the function to "act" ... total(but a weighted sum). ... compare two lists to see which one is "better". ...
    (sci.math)