Code inspection: Equality comparison of floating point numbers
Category: Potential Code Quality Issues
ID: CompareOfFloatsByEqualityOperator
EditorConfig: resharper_compare_of_floats_by_equality_operator_highlighting=[error|warning|suggestion|hint|none]
Language: C#, VB.NET
Requires SWA: No
tip
Using the ==
/!=
operators to compare floating-point numbers is, generally, a bad idea. Floating point values are inherently inaccurate, and comparing them for exact equality is almost never the desired semantics. Comparison via the ==
/!=
operators checks floating-point value representation to be exactly the same, which is very unlikely if you perform any arithmetic operations involving precision loss. For example, let's perform two simple arithmetic operations —
add
0.1
11
times, andmultiply
0.1
by11
— and check whether their floating-point results are equal:
double add = 0;
for (int i = 1; i <= 11; i++)
{
add += 0.1;
}
double multiply = 0.1 * 11;
Console.WriteLine(add == multiply); // false
In a test run, we get add = 1.0999999999999999
and multiply = 1.1000000000000001
(although different runtimes can render different results), so the ==
operator evaluates the comparison to false
.
To do this kind of comparison correctly, we need to specify a tolerance, that is, a value to indicate by how much the result can diverge from the intended value. ReSharper helps us automatically rewrite the comparison as Math.Abs([expression]) < [tolerance]
. The tolerance
value depends on the precision of the calculations you perform. In our example, we can safely rely on a tolerance of 0.000000001
:
double add = 0;
for (int i = 1; i <= 11; i++)
{
add += 0.1;
}
double multiply = 0.1 * 11;
var tolerance = 0.000000001;
Console.WriteLine(Math.Abs(add - multiply) < tolerance); // true
Note that this inspection ignores some values that are often used as "marker values", like 0
, +Infinity
, -Infinity
, NaN
to represent "not yet initialized value" or "value is absent" when non-zero values are otherwise expected.
However, a better way to do that would be the double?
type with the null
value.