Reputation: 1177
I am working on floating point calculation by C# on Win7.
double a, b;
double diff = a -b;
because of floating point precision, sometimes a - b is a very small non-0 number even though a == b. but, sometimes, a and b are close but they are not equal. If I use
if (abs(diff)/(abs(a) + abs(b)) < EPSILON)
my_diff = 0;
else
my_diff = sqrt(diff)
The problem is that how to set value for EPSILON ?
If it is too large, the case of diff is small but a != b cannot be handled correctly.
If it is too small, the case of diff is small but a == b cannot be handled correctly.
a and b should be equal but they are not because there are rounding precision problems. They are got in different ways and they should be equal but they have different precision.
Any help would be appreciated.
Upvotes: 0
Views: 298
Reputation: 222486
The basic problem is:
a
and b
, that would be a and b if calculated exactly but that differ because of floating-point rounding, what can we determine about a and b regarding less than, equal to, and greater than?Suppose we know the maximum possible total error in a
and b
is e. Then we can determine one of:
a
– b
< –e, then a is definitely less than b.a
– b
> +e, then a is definitely greater than b.There are two problems here. One, you have not given us any information that can be used to figure out what e is. It depends greatly on the calculations and values involved, and we do not know what those are. The accumulated error in multiple floating-point operations can range from zero to infinity or can be non-numeric (NaN). In order to know what value to use for your EPSILON
, we must know the history of a
and b
.
(Alternatively, some people guess at e by running many test cases and seeing how much the values vary, or by performing other experiments.)
Two, if a
and b
are within the distance e from each other, then the only possible answer is “We are not sure.” It might be that a and b are equal, and you should set diff
to zero. But, if they are not equal, is it okay if you set diff
to zero? We do not know how that will affect your program. It is up to you to decide. Maybe, instead of accepting a and b as equal in this case, your program should recalculate a
and b
with better arithmetic, in the hope that it will be able to make an accurate determination.
In your particular case, perhaps you are mostly looking to avoid taking the square root of a negative number. If diff
, calculated as a-b
. represents some physical quantity that can never be negative in reality, then perhaps this code would work for you:
double diff = a-b;
if (diff <= 0)
my_diff = 0;
else
my_diff = sqrt(diff);
In IEEE 754 arithmetic, it is impossible for a-b
to be non-zero when a == b
. If you have observed a
and b
to have the same values but for a-b
to be non-zero, then one of the following is true:
a
and b
that are not their true values (e.g., 15-digit displays, but the actual values differ at the 17th digit).a-b
and a == b
were not calculated with IEEE 754 rules. E.g., extra precision was used in the former or not the latter or some process changed the value of one of them between the evaluations of the expressions. (Violating the IEEE 754 rules is not uncommon in Microsoft software. If you showed more of the code that produced a non-zero a-b
and a true a == b
, somebody might be able to help you find where the calculations go wrong.)I used a simple error bound e. In theory, more complicated situations might arise in which the error bound might be larger on one side (favoring a > b) than the other (a < b), and it might be a function of a or of b or other values, or a combination.
Upvotes: 2