A LogFloat is just a Double with a special interpretation.
The logFloat function is presented instead of the constructor,
in order to ensure semantic conversion. At present the Show
instance will convert back to the normal-domain, and so will
underflow at that point. This behavior may change in the future.
Performing operations in the log-domain is cheap, prevents
underflow, and is otherwise very nice for dealing with miniscule
probabilities. However, crossing into and out of the log-domain
is expensive and should be avoided as much as possible. In
particular, if you're doing a series of multiplications as in
lp * logFloat q * logFloat r it's faster to do lp * logFloat
(q * r) if you're reasonably sure the normal-domain multiplication
won't underflow, because that way you enter the log-domain only
once, instead of twice.
Even more particularly, you should avoid addition whenever
possible. Addition is provided because it's necessary at times
and the proper implementation is not immediately transparent.
However, between two LogFloats addition requires crossing the
exp/log boundary twice; with a LogFloat and a regular number
it's three times since the regular number needs to enter the
log-domain first. This makes addition incredibly slow. Again,
if you can parenthesize to do plain operations first, do it!