0

I know that in order to check for equality between two double numbers you have to use the absolute difference between the numbers and compare this difference with a number that is below 1 and greater than zero. This is the simplest method to do because there are more sophisticated methods. A colleague of mine says that if you use the Math.Round for 2 decimal digits for example you can use the exact equality without the above method. So for example if you have number double x; and number double y; you can just write

double x1=Math.Round(x,2);
double y1=Math.Round(y,2);
if(x1 == y1)
 {
    //do something
 }

I don't think that is true. But can you tell me why is this right or wrong?

Dragno
  • 3,027
  • 1
  • 27
  • 41
  • 2
    Round and compare as "equals"??? That's crazy. To check for equality between two numbers (*ANY* two numbers of the same type), you simply... use "equals" (`==`).. To check for equality of "float" vs. "double", you still use "==" (and C will automatically promote before checking). SUGGESTION: read up on [epsilon](https://en.wikipedia.org/wiki/Machine_epsilon), and the classic [what every programmer should know about floating point](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – paulsm4 Apr 15 '23 at 18:14
  • Decimal numerals are not relevant to the properties of real numbers. Forget about decimal digits and decimal representations completely when working with floating-point arithmetic (except decimal-based floating-point). Floating-point arithmetic is about approximating real-number arithmetic. Real numbers do not care about decimal digits. `Math.Round` is a decimal function, so it has no place in floating-point work except for presentation to humans with decimal prejudices. – Eric Postpischil Apr 16 '23 at 13:06

2 Answers2

5

No, because when rounding, 0.004999999 and 0.005000001 will not be considered equal (0.00 vs 0.01 respectively), while with en epsylon of 0.00002 they will be equal.

See Floating point comparison functions for C#.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
2

you have to use the absolute difference between the numbers and compare this difference with a number that is below 1 and greater than zero.

Not exactly. Even granting always subtracting the smaller from the larger, with that plan, 1.99 is equal to 1.01, and 2.49 is equal to 1.51. Instead, replace the 1 with some chosen epsilon value appropriate for the situation, and take the absolute value of the comparison. 1.0 is almost always too large for the epsilon. Something like 0.000001 might be a better fit, but again: how precise you need to be can depend on the situation.

What is the relation between rounding and equality

Imagine you want to represent 1/3 as a decimal. You can't! The decimal value repeats forever. Instead, you have to settle for recording the value up to some number of digits. Effectively, you have rounded the value. This is the nature of base-10 numbers, and it turns out base-2 (binary) has the same issue. In fact, 0.1 works out the same way with base 2: you can't store it exactly as a double value.

Therefore, many of the values you work with in floating point number spaces (of which IEEE-754 is by far the most common, as there is direct CPU support and optimization) are actually just rounded representations of the actual number, and of course this stretches to equality checking.

Now, an alternative strategy for comparing two doubles is rounding them both to the same number of decimal places, and then comparing whether the rounded values are actually equal, as was shown in the question's code sample. This is not recommended. Thanks to the optimization and the inexact nature of floating numbers just explained, it's possible the rounded values end up as subtly different numbers, and will still not be exactly equal.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794