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.