[Haskell-cafe] Working around floating-point inaccuracies

Joachim Durchholz jo at durchholz.org
Sun Aug 5 12:52:52 UTC 2018

Am 05.08.2018 um 14:30 schrieb Michail Pevnev:
> The general pattern to these failures is that one of the coordinates of
> the origin point of the untranslated plane is huge compared to the other
> two - by 4-6 orders of magnitude, while the translation vector is not
> particularly big and has about the same magnitude as the two smaller
> coordinates.

I haven't checked whether this is really the case, but such failures 
tend to happen when the math is "badly conditioned" - i.e. if you're 
doing the equivalent of a/(b-c) somewhere, where b and c are so close to 
each other that most or all significant digits cancel out.
Geometrically, a typical task would be trying to find the intersection 
of almost-parallel linear objects.

Either your test code has the same instabilities as the tested code. In 
this case, your tested code isn't suitable for certain classes of 
situations; you'll want to find out which these are, and document them. 
Or try and find a different algorithm.
In this case: Congratulations, testing revealed a real problem in your 
code :-)

Or your test code has different instabilities. In that case, rewrite 
your test code.
A different way to phrase this is: Your test code makes different 
assumptions (about numeric stability, that is) than the code under test.

The *clean* way to deal with this is to calculate the error bounds, 
document them, and write test code that checks whether the code under 
test is behaving within the calculated error bounds.
However, this is a pretty hairy thing to do; expect to spend several 
weeks to get the math worked out - or a few days with a numerics expert 
who already has seen it all.
So maybe you'll want to think about alternatives; which of these are 
relevant depends a lot on what you're using your code for, and what 
kinds of qualities you want to achieve.

Yet another approach might be using Rational instead of float.
Rational is a net win only if you don't have iterations in your code, 
otherwise your numerators and denominators will grow on each iteration, 
eating up your memory.


More information about the Haskell-Cafe mailing list