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') (m-m') recip (L s m) = L s (-m) fromRational x = (fromInteger $ numerator x) / (fromInteger $ denominator x)