Of course one should never compare floating point values that result from a calculation for equality, but always use a small tolerance, e.g.:
double value1 = ... double value2 = ... if (Math.Abs(value1 - value2) < tolerance * Math.Abs(value1)) { ... values are close enough }
But if I use Math.Round can I always be sure that the resulting value will be consistent, i.e. will the following Assert always succeed, even when the rounded value is a value that can't be represented exactly by a double?
public static void TestRound(double value1, double value2, int decimals) { double roundedValue1 = Math.Round(value1, decimals); double roundedValue2 = Math.Round(value2, decimals); string format = "N" + decimals.ToString(); if (roundedValue1.ToString(format) == roundedValue2.ToString(format)) { // They rounded to the same value, was the rounding exact? Debug.Assert(roundedValue1 == roundedValue2); } }
If not please provide a counterexample.
EDIT
Thanks to astander for a counterexample generated by brute force that proves the result is not "consistent" in the general case. This counterexample has 16 significant digits in the rounded result - it also fails in the same way when scaled thus:
double value1 = 10546080000034341D; double value2 = 10546080000034257D; int decimals = 0; TestRound(value1, value2, decimals);
However I'd also be interested in a more mathematical explanation. Bonus upvotes for any of the more mathematical Stackoverflowers who can do any of the following:
Find a counterexample where the rounded result has fewer than 16 significant digits.
Identify a range of values for which the rounded result will always be "consistent" as defined here (e.g. all values where the number of significant digits in the rounded result is < N).
Provide an algorithmic method to generate counterexamples.