- To: Jamie Wilkinson <jaq@xxxxxxxxxxxxxx>
- Subject: Re: Floating point comparisons, a <= b <= c operations in Python (was Re: [coders] Python newbie question
- From: Peter Miller <millerp@xxxxxxxxxxxxxxxx>
- Date: Thu, 16 Nov 2006 11:27:12 +1100
- Cc: coders@xxxxxxxxxxx
On Thu, 2006-11-16 at 10:46 +1100, Jamie Wilkinson wrote:
> What's better:
>
> if expected - epsilon <= computation()<= expected + epsilon:
>
> versus:
>
> if abs(computation() - expected) >= epsilon:
Epsilon if a function of the number of bits in the mantissa, but not the
number of bits of exponent. So a better test tends to be
if (fabs(computation()/expected) > 1 + epsilon)
blah
but that makes matters worse, because the division loses more precision,
so the better but less obvious C code is
int expected_exponent;
frexp(expected, &expected_exponent);
double scaled_epsilon = ldexp(unscaled_epsilon, expected_exponent);
if (fabs(computation() - expected) >= scaled_epsilon)
blah
where the "unscaled_epsilon" is for the case where you are comparing 1
against 1, and the scaled_epsilon adjusts for the expected magnitude.
Note that ldexp and frexp tend to be very fast (compared to a floating
point subtraction), because they are integer operations with a little
bit bashing.
Fabs is fast, too, because in IEEE floats, it simply clears a singe bit.
Many other ancient pre-IEEE-std floating point formats have the same
property.
So, yes, fabs() and a single compare is faster than two comparisons,
because the comparisons do two relatively expensive (compared to fabs)
floating point subtractions, not just one.
It is worth noting that
expected + unscaled_epsilon == expected
when the exponent of "expected" exceeds the number of bits in the
mantissa. But is degraded and not very useful long before then.