Safe Haskell | None |
---|---|
Language | Haskell2010 |
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, Foldable f, Ord a) => f (LogField a) -> LogField a
- accurateProduct :: (ExpField 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 LogField
s 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, Foldable f, Ord a) => f (LogField a) -> LogField a Source #
O(n). Compute the sum of a finite list of LogField
s, 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, Foldable f) => f (LogField a) -> LogField a Source #
O(n). Compute the product of a finite list of LogField
s,
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