Portability | portable (with CPP, FFI) |
---|---|

Stability | stable |

Maintainer | wren@community.haskell.org |

This module presents a type 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 Data.Number.LogFloat.Signed
for doing signed log-domain calculations.

- module Data.Number.Transfinite
- module Data.Number.RealToFrac
- data LogFloat
- logFloat :: (Real a, RealToFrac a Double) => a -> LogFloat
- fromLogFloat :: (Fractional a, Transfinite a, RealToFrac Double a) => LogFloat -> a
- logToLogFloat :: (Real a, RealToFrac a Double) => a -> LogFloat
- logFromLogFloat :: (Fractional a, Transfinite a, RealToFrac Double a) => LogFloat -> a
- log1p :: Double -> Double
- expm1 :: Double -> Double

# Exceptional numeric values

module Data.Number.Transfinite

module Data.Number.RealToFrac

`LogFloat`

data type

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 `LogFloat`

s 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!

## Isomorphism to normal-domain

logFloat :: (Real a, RealToFrac a Double) => a -> LogFloatSource

Constructor which does semantic conversion from normal-domain to log-domain. Throws errors on negative input.

fromLogFloat :: (Fractional a, Transfinite a, RealToFrac Double a) => LogFloat -> aSource

Return our log-domain value back into normal-domain. Beware of overflow/underflow.

## Isomorphism to log-domain

logToLogFloat :: (Real a, RealToFrac a Double) => a -> LogFloatSource

Constructor which assumes the argument is already in the
log-domain. Throws errors on `notANumber`

input.

logFromLogFloat :: (Fractional a, Transfinite a, RealToFrac Double a) => LogFloat -> aSource

Return the log-domain value itself without conversion.

# Accurate versions of logarithm/exponentiation

log1p :: Double -> DoubleSource

Definition: `log1p == log . (1+)`

. The C language provides a
special definition for `log1p`

which is more accurate than doing
the naive thing, especially for very small arguments. For example,
the naive version underflows around `2 ** -53`

, whereas the
specialized version underflows around `2 ** -1074`

. This function
is used by (`+`

) and (`-`

) on `LogFloat`

.

*This installation was compiled to use the specialized version.*

expm1 :: Double -> DoubleSource

Definition: `expm1 == (subtract 1) . exp`

. The C language
provides a special definition for `expm1`

which is more accurate
than doing the naive thing, especially for very small arguments.
This function isn't needed internally, but is provided for
symmetry with `log1p`

.

*This installation was compiled to use the specialized version.*