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
How to Implement Option Buttons and Change the Button Color in Pygame
Why Use Abstract Base Classes in Python
Is It Still Necessary to Install Cuda Before Using the Conda Tensorflow-Gpu Package
High-Precision Clock in Python
Random State (Pseudo-Random Number) in Scikit Learn
How to Make Environment Variable Changes Stick in Python
Conda' Is Not Recognized as Internal or External Command
Calculation Error with Pow Operator
Global Variable from a Different File Python
How to Use a Multiprocessing.Manager()
How to Pass a User Defined Argument in Scrapy Spider
Serialize Python Dictionary to Xml