logfloat-0.8.3: Log-domain floating point numbersSource codeContentsIndex
Data.Number.LogFloat
Portabilityportable
Stabilitystable
Maintainerwren@community.haskell.org
Contents
Documentation Note
IEEE floating-point special values
Basic functions
LogFloat data type and conversion functions
Description

This module presents a class for storing numbers in the log-domain. The main reason for doing this is to prevent underflow when multiplying many small probabilities as is done in Hidden Markov Models and other statistical models often used for natural language processing. The log-domain also helps prevent overflow when multiplying many large numbers. In rare cases it can speed up numerical computation (since addition is faster than multiplication, though logarithms are exceptionally slow), but the primary goal is to improve accuracy of results. A secondary goal has been to maximize efficiency since these computations are frequently done within a O(n^3) loop.

The LogFloat of this module is restricted to non-negative numbers for efficiency's sake, see the forthcoming Data.Number.LogFloat.Signed for doing signed log-domain calculations.

Synopsis
infinity :: Fractional a => a
negativeInfinity :: Fractional a => a
notANumber :: Fractional a => a
log :: Floating a => a -> a
toFractional :: (Real a, Fractional b) => a -> b
data LogFloat
logFloat :: Real a => a -> LogFloat
logToLogFloat :: Real a => a -> LogFloat
fromLogFloat :: Floating a => LogFloat -> a
logFromLogFloat :: Floating a => LogFloat -> a
Documentation Note
If you see no module description above, then the lhs2hs script was not run correctly. Please rebuild the documentation or see: http://code.haskell.org/~wren/logfloat/dist/doc/html/logfloat/
IEEE floating-point special values

GHC.Real defines infinity and notANumber as Rational. We export variants which are polymorphic because that can be more helpful at times.

BUG: At present these constants are broken for Ratio types including Rational, since Ratio types do not typically permit a zero denominator. In GHC (6.8.2) the result for infinity is a rational with a numerator sufficiently large that fromRational will yield infinity for Float and Double. In Hugs (September 2006) it yields an arithmetic overflow error. For GHC, our notANumber yields 0%1 rather than 0%0 as GHC.Real does.

infinity :: Fractional a => aSource
negativeInfinity :: Fractional a => aSource
notANumber :: Fractional a => aSource
Basic functions
log :: Floating a => a -> aSource

Since the normal log throws an error on zero, we have to redefine it in order for things to work right. Arguing from limits it's obvious that log 0 == negativeInfinity.

If you're using some Floating type that's not built in, verify this equation holds for your 0 and negativeInfinity. If it doesn't, then you should avoid importing our log and will probably want converters to handle the discrepency.

toFractional :: (Real a, Fractional b) => a -> bSource
The most generic numeric converter I can come up with. All the built-in numeric types are Real, though Int and Integer aren't Fractional.
LogFloat data type and conversion functions
data LogFloat Source

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!

show/hide Instances
logFloat :: Real a => a -> LogFloatSource
A constructor which does semantic conversion from normal-domain to log-domain.
logToLogFloat :: Real a => a -> LogFloatSource
Constructor which assumes the argument is already in the log-domain.
fromLogFloat :: Floating a => LogFloat -> aSource
Return our log-domain value back into normal-domain. Beware of overflow/underflow.
logFromLogFloat :: Floating a => LogFloat -> aSource
Return the log-domain value itself without costly conversion
Produced by Haddock version 2.4.2