| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
NumHask.Data.LogField
Synopsis
- data LogField a
- logField :: ExpField a => a -> LogField a
- fromLogField :: ExpField a => LogField a -> a
- logToLogField :: a -> LogField a
- logFromLogField :: LogField a -> a
- accurateSum :: (ExpField a, Subtractive a, Foldable f, Ord a) => f (LogField a) -> LogField a
- accurateProduct :: (ExpField a, Subtractive a, Foldable f) => f (LogField a) -> LogField a
- pow :: (ExpField a, LowerBoundedField a, Ord a) => LogField a -> a -> LogField a
LogField
Module : Data.Number.LogFloat Copyright : Copyright (c) 2007--2015 wren gayle romano License : BSD3 Maintainer : wren@community.haskell.org Stability : stable Portability : portable (with CPP, FFI) Link : https://hackage.haskell.org/package/logfloat
A LogField is just a Field with a special interpretation.
The LogField 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 hence will
underflow at that point. This behavior may change in the future.
Because logField performs the semantic conversion, we can use
operators which say what we *mean* rather than saying what we're
actually doing to the underlying representation. That is,
equivalences like the following are true[1] thanks to type-class
overloading:
logField (p + q) == logField p + logField q logField (p * q) == logField p * logField q
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 * LogField q * LogField r it's faster to do lp * LogField
(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. Also note that, for precision, if you're
doing more than a few multiplications in the log-domain, you
should use product rather than using '(*)' repeatedly.
Even more particularly, you should avoid addition whenever
possible. Addition is provided because sometimes we need it, and
the proper implementation is not immediately apparent. However,
between two LogFields addition requires crossing the exp/log
boundary twice; with a LogField and a Double 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 normal-domain operations first, do it!
- 1
- That is, true up-to underflow and floating point fuzziness. Which is, of course, the whole point of this module.
Instances
logField :: ExpField a => a -> LogField a Source #
Constructor which does semantic conversion from normal-domain
to log-domain. Throws errors on negative and NaN inputs. If p
is non-negative, then following equivalence holds:
logField p == logToLogField (log p)
fromLogField :: ExpField a => LogField a -> a Source #
Semantically convert our log-domain value back into the normal-domain. Beware of overflow/underflow. The following equivalence holds (without qualification):
fromLogField == exp . logFromLogField
Isomorphism to log-domain
logToLogField :: a -> LogField a Source #
Constructor which assumes the argument is already in the log-domain.
logFromLogField :: LogField a -> a Source #
Return the log-domain value itself without conversion.
Additional operations
accurateSum :: (ExpField a, Subtractive a, Foldable f, Ord a) => f (LogField a) -> LogField a Source #
O(n). Compute the sum of a finite list of LogFields, being
careful to avoid underflow issues. That is, the following
equivalence holds (modulo underflow and all that):
LogField . accurateSum == accurateSum . map LogField
N.B., this function requires two passes over the input. Thus, it is not amenable to list fusion, and hence will use a lot of memory when summing long lists.
accurateProduct :: (ExpField a, Subtractive a, Foldable f) => f (LogField a) -> LogField a Source #
O(n). Compute the product of a finite list of LogFields,
being careful to avoid numerical error due to loss of precision.
That is, the following equivalence holds (modulo underflow and
all that):
LogField . accurateProduct == accurateProduct . map LogField