Testing Floating Point Equality

Test for floating point equality. (FE_FLOATING_POINT_EQUALITY)

Problem 1:

For the FE_FLOATING_POINT_EQUALITY issue, you should not be comparing two float values directly with the == operator, since due to tiny rounding errors, the values might be semantically "equal" for your application even if the condition value1 == value2 does not hold true.

In order to fix this, modify your code as follows:

private boolean equals(final Quantity other) {
return (Math.abs(this.mAmount - convertedAmount(other)) < EPSILON);
}

Where EPSILON is a constant that you should define in your code, and represents small differences that are acceptable to your application, e.g. .0000001.

Problem 2:

For the EQ_COMPARETO_USE_OBJECT_EQUALS issue: It is strongly recommended that wherever x.compareTo(y) returns zero, x.equals(y) should be true. In your code you have implemented compareTo, but you have not overriden equals, so you are inheriting the implementation of equals from Object, and the above condition is not met.

In order to fix this, override equals (and perhaps hashCode) in your class, so that when x.compareTo(y) returns 0, then x.equals(y) will return true.

Testing for float equality in C

float has less precision than double, which would be the default type used for floating point literals. Since 6.7 cannot be represented with a finite number of binary digits, the less precise float representation does not equal the double representation.

Can floating point equality and inequality tests be assumed to be consistent and repeatable?

Provided the x and y in the question are identifiers (rather than abbreviations for expressions generally, such as x standing for b + sqrt(c)), then the C++ standard requires (x >= y) == (x > y || x == y) to be true.

C++ 2017 (draft N4659) 8 13 allows floating-point expressions to be evaluated with greater precision and range than required by their nominal types. For example, while evaluating an operator with float operands, the implementation may use double arithmetic. However, footnote 64 there refers us to 8.4, 8.2.9, and 8.18 to understand that the cast and assignment operators must perform their specific conversions, which produce a value representable in the nominal type.

Thus, once x and y have been assigned values, there is no excess precision, and they do not have different values in different uses. Then (x >= y) == (x > y || x == y) must be true because it is evaluated as it appears and is necessarily mathematically true.

The existence of GCC bug 323 means you cannot rely on GCC when compiling for i386, but this is due to a bug in GCC which violates the C++ standard. Standard C++ does not permit this.

If comparisons are made between expressions, as in:

double y = b + sqrt(c);
if (y != b + sqrt(c))
std::cout << "Unequal\n";

then the value assigned to y may differ from the value computed for the right operator of b + sqrt(c), and the string may be printed, because b + sqrt(c) may have excess precision, whereas y must not.

Since casts are also required to remove excess precision, then y != (double) (b + sqrt(c)) should always be false (given the definition of y above).

How should I do floating point comparison?

Comparing for greater/smaller is not really a problem unless you're working right at the edge of the float/double precision limit.

For a "fuzzy equals" comparison, this (Java code, should be easy to adapt) is what I came up with for The Floating-Point Guide after a lot of work and taking into account lots of criticism:

public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);

if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / (absA + absB) < epsilon;
}
}

It comes with a test suite. You should immediately dismiss any solution that doesn't, because it is virtually guaranteed to fail in some edge cases like having one value 0, two very small values opposite of zero, or infinities.

An alternative (see link above for more details) is to convert the floats' bit patterns to integer and accept everything within a fixed integer distance.

In any case, there probably isn't any solution that is perfect for all applications. Ideally, you'd develop/adapt your own with a test suite covering your actual use cases.

What is the best way to compare floats for almost-equality in Python?

Python 3.5 adds the math.isclose and cmath.isclose functions as described in PEP 485.

If you're using an earlier version of Python, the equivalent function is given in the documentation.

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

rel_tol is a relative tolerance, it is multiplied by the greater of the magnitudes of the two arguments; as the values get larger, so does the allowed difference between them while still considering them equal.

abs_tol is an absolute tolerance that is applied as-is in all cases. If the difference is less than either of those tolerances, the values are considered equal.

Ideal way to test for practical floating point equality in c#

If there was a comparison that met your criteria

  • Works 100% of the time
  • Easy to read/understand
  • High performance

then your favorite programming language would already define comparison operators on floating-point types to do that.

But in reality, the "right" thing to do varies widely based on the meaning of the stored number. There is no one-size-fits-all relaxation of floating point equality!!!

You will have to think about the data you have, its accuracy, measurement error, quantization error, rounding error in calculations, and what decisions you are making with it. Trying to delegate this thinking to someone making general purpose tools is doomed to fail.

Even defining "equal enough" with deep domain knowledge is subject to a lot of pitfalls, for example you may1 find that this happens:

  • Key already exists in unordered_map, but "find" returns as not found

1 By "may" I mean this happens more often than your "ideal" floating-point comparison works.



Related Topics



Leave a reply



Submit