Exact equality comparison against a floating-point literal

ID

vbnet.correctness.float_equality

Severity

high

Remediation Complexity

medium

Remediation Risk

medium

Remediation Effort

low

Resource

Numeric

Language

VB.NET

Description

Flags an exact equality or inequality test in which one operand is a floating-point literal — a value with a decimal point such as 21.5, an exponent form such as 1.0E-6 or 1E-9, or a literal carrying an F, R, ! or # suffix — on either side of the operator. Because = also means assignment in VB.NET, the equality form is matched only where the context makes it a comparison: inside an If …​ Then condition or in a Return. The <> form is matched anywhere. Two things are deliberately outside its reach: a comparison in which both sides are variables, since no literal is present to key on, and Decimal literals written with the D or @ suffix, which do compare exactly and are the correct type for money. Ordering comparisons such as reading > 21.5 are well behaved and are not reported.

Rationale

Double and Single are binary floating point and cannot represent most decimal fractions exactly, so a value that is conceptually equal to the literal generally differs from it in the last bits once any arithmetic, parsing or unit conversion has touched it. The test then fails where the author expects it to succeed — and with <>, succeeds where they expect it to fail. The failure mode is the awkward kind: the comparison is not reliably wrong, so the branch fires for some inputs and not others, and the outcome can shift between compilers, platforms and optimisation settings. A thermostat that never registers reaching its set point, or a loop that never sees its terminating value, are typical results.

The following code illustrates the pattern detected by this rule:

Public Function AtTarget(ByVal reading As Double) As Boolean
    ' FLAGGED: Exact equality comparison against a floating-point literal
    If reading = 21.5 Then
        Return True
    End If
    Return False
End Function

Remediation

Compare against a tolerance instead of testing for exact equality. When the values must compare exactly, as with money, use Decimal rather than Double or Single.

' Before: rarely True once `reading` has been through any arithmetic
If reading = 21.5 Then
    HoldTemperature()
End If

' After
If Math.Abs(reading - 21.5) < 0.001 Then
    HoldTemperature()
End If

Configuration

This detector does not need any configuration.