Reputation: 64196
As I understand the values of floating point types must be compared carefully to avoid issues with inherent floating point errors. This can be improved by comparing values with an error threshold.
For example, the following solution is more usable than a straightforward x == y
test:
static float CompareRelativeError(float x, float y) {
return Math.Abs(x - y) / Math.Max(Math.Abs(x), Math.Abs(y));
}
static bool CompareAlmostEqual(float x, float y, float delta) {
return x == y || CompareRelativeError(x, y) < delta;
}
// apologies if this is a poor example
if (CompareAlmostEqual(1f/10f, 0.1f)) { ... }
The above solution was derived from the following resource: Is it safe when compare 2 float/double directly in Java?
Whilst I haven't been able to find any literature to confirm this, to me it seems that the same must hold true for comparisons like x > y
. For example, if x
and y
are essentially equal, how can one be greater than the other...
static bool CompareGreater(float x, float y, float delta) {
return x > y && !CompareAlmostEqual(x, y, delta);
}
And thus the following would be valid for x >= y
:
static bool CompareGreaterOrEqual(float x, float y) {
return x >= y;
}
Are my assumptions correct?
Upvotes: 4
Views: 5815
Reputation: 300499
Equality testing is precisely the reason why the delta (or epsilon) technique is used for floating point values.
e.g. we want 3 to be equal to 2.999999... to some precision.
So your CompareGreaterOrEqual
method is not sufficient when defined as:
static bool CompareGreaterOrEqual(float x, float y) {
return x >= y;
}
It should be:
static bool CompareGreaterOrEqual(float x, float y, float delta) {
return x >= y || CompareAlmostEqual(x, y, delta);
}
Note: x >= y
in first test could just be x > y
since the delta comparison takes care of equality:
static bool CompareGreaterOrEqual(float x, float y, float delta) {
return x > y || CompareAlmostEqual(x, y, delta);
}
Upvotes: 4
Reputation: 6260
Since we have already agreed that the operator =
in this case is done through CompareAlmostEqual
, then it would also make sense to use it in CompareGreaterOrEqual
as well.
static bool CompareGreaterOrEqual(float x, float y, float delta) {
return x >= y || CompareAlmostEqual(x, y, delta);
}
Also, while it highly depends on how you would utilize these functions, I would also make delta
a constant variable that is used throughout the class to ensure using the same value (instead of passing it around as an argument).
Upvotes: 2