module Data.Lognum (Lognum)
where
import Data.Ratio
data Lognum t = L !Int !t deriving (Eq, Ord)
fromFloating :: (Floating t, Ord t) => t -> Lognum t
fromFloating a = case a `compare` 0 of
LT -> L (1) (log $ a)
EQ -> L 0 0
GT -> L 1 (log a)
toFloating :: (Floating t, Ord t) => Lognum t -> t
toFloating (L s m) = case s of
1 -> negate $ exp m
0 -> 0
1 -> exp m
logify2 :: (Floating t, Ord t) => (t -> t -> t) -> (Lognum t -> Lognum t -> Lognum t)
logify2 (*) a b = fromFloating $ toFloating a * toFloating b
instance (Floating t, Ord t) => Show (Lognum t) where
show = show . toFloating
instance (Floating t, Ord t) => Num (Lognum t) where
(+) = logify2 (+)
(L s m) * (L s' m') = if s == 0 || s' == 0 then
L 0 0
else
L (s*s') (m+m')
() = logify2 ()
negate (L s m) = L (negate s) m
abs (L s m) = L (abs s) m
signum (L s m) = (L s 0)
fromInteger = fromFloating . fromInteger
instance (Floating t, Ord t) => Fractional (Lognum t) where
_ / (L 0 _) = error "division by zero"
(L s m) / (L s' m') = L (s*s') (mm')
recip (L s m) = L s (m)
fromRational x = (fromInteger $ numerator x) / (fromInteger $ denominator x)