This rule raises an issue when methods that compare values for sorting or ordering purposes compare floating-point values using subtraction or
simple relational operators (<, >, ⇐, >=) instead of dedicated comparison utilities
designed for floating-point numbers.
In Java, this specifically applies to compareTo() methods (from the Comparable interface) and compare()
methods (from the Comparator interface).
Comparing floating-point values (single or double precision) using subtraction or simple comparison operators does not correctly handle special
IEEE 754 values such as NaN (Not a Number) and negative zero (-0.0).
The IEEE 754 floating-point standard defines specific rules for these edge cases:
NaN is not equal to any value, including itself. Any comparison with NaN (except inequality checks) should return
false.-0.0) and positive zero (+0.0) are considered equal when using equality operators, but they should be
distinguished in ordering operations.NaN should be considered greater than all other values (including positive infinity) in a total ordering.When you implement comparison using subtraction (e.g., converting the difference between two floating-point values to an integer result), several problems occur:
NaN produces NaN, which when cast to an integer becomes
0, incorrectly suggesting the values are equal.(-0.0) - (+0.0) produces -0.0, which becomes 0 when cast,
making the values appear equal in both directions, which is correct. However, the general approach is still flawed for other cases.Using simple comparison operators like < or > also fails:
NaN (except inequality) returns false, breaking the transitivity requirement of comparison interface
contracts.Standard library functions designed for floating-point comparison handle all these edge cases correctly. They impose a total ordering that treats:
NaN as equal to itself and greater than all other values (including positive infinity)-0.0 as less than +0.0This ensures that comparison methods satisfy the general contract required by comparison interfaces and comparator implementations.
In Java, use the Float.compare() and Double.compare() methods for proper floating-point comparison. These methods
correctly implement the total ordering described above and satisfy the contracts of the Comparable interface and Comparator
implementations.
Using incorrect floating-point comparison can lead to several serious issues:
NaN and special values breaks these guarantees.NaN values, making bugs
difficult to reproduce and diagnose.In Java, these requirements are formalized in the Comparable and Comparator contracts.
Replace subtraction-based comparison with Double.compare() or Float.compare(). These methods return a negative integer,
zero, or positive integer as the first argument is less than, equal to, or greater than the second, while correctly handling all IEEE 754 special
cases.
This fix always applies when floating-point values are compared in ordering methods. There is no scenario where subtraction-based comparison of
float or double values in a compareTo() or compare() method is correct, because it silently
mishandles NaN, negative zero, and values whose difference is smaller than 1.
This rule does not flag subtraction of integer types or floating-point comparisons outside of ordering methods.
If you believe the finding is a false positive, verify that the flagged expression genuinely involves float or double
operands in a compareTo() or compare() method. If it does, the finding is not a false positive — the subtraction approach is
always incorrect for these types in ordering contexts, even when the values happen to be well-bounded in practice.
class Position implements Comparable<Position> {
private double latitude;
private double longitude;
@Override
public int compareTo(Position other) {
int latComparison = (int)(this.latitude - other.latitude); // Noncompliant
if (latComparison != 0) {
return latComparison;
}
return (int)(this.longitude - other.longitude); // Noncompliant
}
}
class Position implements Comparable<Position> {
private double latitude;
private double longitude;
@Override
public int compareTo(Position other) {
int latComparison = Double.compare(this.latitude, other.latitude);
if (latComparison != 0) {
return latComparison;
}
return Double.compare(this.longitude, other.longitude);
}
}