-- | A simple implementation of floating point numbers with a selectable -- precision. The number of digits in the mantissa is selected by the -- 'Epsilon' type class from the "Fixed" module. -- -- The numbers are stored in base 10. module Data.Number.BigFloat( BigFloat, Epsilon, Eps1, EpsDiv10, Prec10, Prec50, PrecPlus20 ) where import Numeric(showSigned) import Data.Number.Fixed import qualified Data.Number.FixedFunctions as F base :: (Num a) => a base = 10 -- This representation is stupid, two Integers makes more sense, -- but is more work. -- | Floating point number where the precision is determined by the type /e/. data BigFloat e = BF (Fixed e) Integer deriving (Eq) instance (Epsilon e) => Show (BigFloat e) where showsPrec = showSigned showBF -- Assumes base is 10 where showBF (BF m e) = showsPrec 0 m . showString "e" . showsPrec 0 e instance (Epsilon e) => Num (BigFloat e) where BF m1 e1 + BF m2 e2 = bf (m1' + m2') e where (m1', m2') = if e == e1 then (m1, m2 / base^(e-e2)) else (m1 / base^(e-e1), m2) e = e1 `max` e2 -- Do - via negate BF m1 e1 * BF m2 e2 = bf (m1 * m2) (e1 + e2) negate (BF m e) = BF (-m) e abs (BF m e) = BF (abs m) e signum (BF m _) = bf (signum m) 0 fromInteger i = bf (fromInteger i) 0 instance (Epsilon e) => Real (BigFloat e) where toRational (BF e m) = toRational e * base^^m instance (Epsilon e) => Ord (BigFloat e) where compare x y = compare (toRational x) (toRational y) instance (Epsilon e) => Fractional (BigFloat e) where recip (BF m e) = bf (base / m) (-(e + 1)) -- Take care not to lose precision for small numbers fromRational x | x == 0 || abs x >= 1 = bf (fromRational x) 0 | otherwise = recip $ bf (fromRational (recip x)) 0 -- normalizing constructor -- XXX The scaling is very inefficient bf :: (Epsilon e) => Fixed e -> Integer -> BigFloat e bf m e | m == 0 = BF 0 0 | m < 0 = - bf (-m) e | m >= base = bf (m / base) (e + 1) | m < 1 = bf (m * base) (e - 1) | otherwise = BF m e instance (Epsilon e) => RealFrac (BigFloat e) where properFraction x@(BF m e) = if e < 0 then (0, x) else let (i, f) = properFraction (m * base^^e) in (i, bf f 0) instance (Epsilon e) => Floating (BigFloat e) where pi = bf pi 0 sqrt = toFloat1 F.sqrt exp = toFloat1 F.exp log = toFloat1 F.log sin = toFloat1 F.sin cos = toFloat1 F.cos tan = toFloat1 F.tan asin = toFloat1 F.asin acos = toFloat1 F.acos atan = toFloat1 F.atan sinh = toFloat1 F.sinh cosh = toFloat1 F.cosh tanh = toFloat1 F.tanh asinh = toFloat1 F.asinh acosh = toFloat1 F.acosh atanh = toFloat1 F.atanh instance (Epsilon e) => RealFloat (BigFloat e) where floatRadix _ = base floatDigits (BF m _) = floor $ logBase base $ recip $ fromRational $ precision m floatRange _ = (minBound, maxBound) decodeFloat x@(BF m e) = let d = floatDigits x in (round $ m * base^d, fromInteger e - d) encodeFloat m e = bf (fromInteger m) (toInteger e) exponent (BF _ e) = fromInteger e significand (BF m _) = BF m 0 scaleFloat n (BF m e) = BF m (e + toInteger n) isNaN _ = False isInfinite _ = False isDenormalized _ = False isNegativeZero _ = False isIEEE _ = False toFloat1 :: (Epsilon e) => (Rational -> Rational -> Rational) -> BigFloat e -> BigFloat e toFloat1 f x@(BF m e) = fromRational $ f (precision m * scl) (toRational m * scl) where scl = base^^e