{- | Module : Numeric.QD.QuadDouble Copyright : (c) Claude Heiland-Allen 2011 License : BSD3 Maintainer : claude@mathr.co.uk Stability : unstable Portability : portable High-level interface to libqd for quad-double numbers. -} {-# LANGUAGE DeriveDataTypeable #-} module Numeric.QD.QuadDouble ( QuadDouble(QuadDouble) , toDouble , fromDouble , toDoubleDouble , fromDoubleDouble , sqr ) where import Foreign (Ptr, alloca, castPtr, Storable(..), with) import System.IO.Unsafe (unsafePerformIO) import Foreign.C (CDouble, CInt) import Data.Bits (shiftL) import Data.Ratio ((%)) import Data.Typeable (Typeable(..)) import Numeric (readSigned, readFloat) import Text.FShow.Raw (BinDecode(..), DecimalFormat(..), FormatStyle(Generic), decimalFormat) import Numeric.QD.DoubleDouble (DoubleDouble(DoubleDouble)) import Numeric.QD.QuadDouble.Raw.Safe ( c_qd_add , c_qd_sub , c_qd_mul , c_qd_div , c_qd_pi , c_qd_exp , c_qd_sqrt , c_qd_log , c_qd_sin , c_qd_cos , c_qd_tan , c_qd_asin , c_qd_acos , c_qd_atan , c_qd_sinh , c_qd_cosh , c_qd_tanh , c_qd_asinh , c_qd_acosh , c_qd_atanh , c_qd_comp , c_qd_neg , c_qd_abs , c_qd_sqr ) -- | @'QuadDouble' a b c d@ represents the unevaluated sum @a + b + c + d@. data QuadDouble = QuadDouble {-# UNPACK #-} !CDouble {-# UNPACK #-} !CDouble {-# UNPACK #-} !CDouble {-# UNPACK #-} !CDouble deriving Typeable instance BinDecode QuadDouble where decode (QuadDouble a b c d) = let repack (0, 0 ) (bm, be) = (bm, be) repack (am, ae) (0, 0 ) = (am, ae) repack (am, ae) (bm, be) = (am `shiftL` (ae - be) + bm, be) in foldl1 repack $ map decodeFloat [a, b, c, d] showDigits _ = 70 -- FIXME somewhat arbitrary -- FIXME check these instance DecimalFormat QuadDouble where nanTest (QuadDouble a _ _ _) = isNaN a infTest (QuadDouble a _ _ _) = isInfinite a negTest x = x < 0 -- | Convert to 'Double'. toDouble :: QuadDouble -> Double toDouble (QuadDouble a _ _ _) = realToFrac a -- | Convert from 'Double'. fromDouble :: Double -> QuadDouble fromDouble a = QuadDouble (realToFrac a) 0 0 0 -- | Convert to 'DoubleDouble'. toDoubleDouble :: QuadDouble -> DoubleDouble toDoubleDouble (QuadDouble a b _ _) = DoubleDouble a b -- | Convert from 'DoubleDouble'. fromDoubleDouble :: DoubleDouble -> QuadDouble fromDoubleDouble (DoubleDouble a b) = QuadDouble a b 0 0 instance Eq QuadDouble where a == b = a `compare` b == EQ a /= b = a `compare` b /= EQ instance Ord QuadDouble where a `compare` b = unsafePerformIO $ with a $ \p -> with b $ \q -> alloca $ \r -> do c_qd_comp (castPtr p) (castPtr q) (castPtr r) i <- peek r return $ i `compare` (0 :: CInt) instance Num QuadDouble where (+) = lift_qd_qd_qd c_qd_add (*) = lift_qd_qd_qd c_qd_mul (-) = lift_qd_qd_qd c_qd_sub negate = lift_qd_qd c_qd_neg abs = lift_qd_qd c_qd_abs signum a = case a `compare` 0 of { LT -> -1 ; EQ -> 0 ; GT -> 1 } fromInteger i = fromRational (i % 1) -- | Square a 'QuadDouble' number. sqr :: QuadDouble -> QuadDouble sqr = lift_qd_qd c_qd_sqr instance Fractional QuadDouble where (/) = lift_qd_qd_qd c_qd_div recip b = 1 / b fromRational k = let a = fromRational k ka = k - toRational a b = fromRational ka kb = ka - toRational b c = fromRational kb kc = kb - toRational c d = fromRational kc in QuadDouble a b c d instance Real QuadDouble where toRational (QuadDouble a b c d) = toRational a + toRational b + toRational c + toRational d instance RealFrac QuadDouble where properFraction k = let (n, r) = properFraction (toRational k) in (n, fromRational r) truncate = truncate . toRational round = round . toRational ceiling = ceiling . toRational floor = floor . toRational instance Floating QuadDouble where pi = unsafePerformIO $ alloca $ \r -> c_qd_pi (castPtr r) >> peek r exp = lift_qd_qd c_qd_exp sqrt = lift_qd_qd c_qd_sqrt log = lift_qd_qd c_qd_log sin = lift_qd_qd c_qd_sin cos = lift_qd_qd c_qd_cos tan = lift_qd_qd c_qd_tan asin = lift_qd_qd c_qd_asin acos = lift_qd_qd c_qd_acos atan = lift_qd_qd c_qd_atan sinh = lift_qd_qd c_qd_sinh cosh = lift_qd_qd c_qd_cosh tanh = lift_qd_qd c_qd_tanh asinh = lift_qd_qd c_qd_asinh acosh = lift_qd_qd c_qd_acosh atanh = lift_qd_qd c_qd_atanh -- instance Enum QuadDouble -- FIXME instance Show QuadDouble where show = decimalFormat (Generic Nothing) Nothing instance Read QuadDouble where readsPrec _ = readSigned readFloat instance Storable QuadDouble where sizeOf _ = 4 * sizeOf (0 :: CDouble) alignment _ = alignment (0 :: CDouble) peek p = do let q = castPtr p a <- peekElemOff q 0 b <- peekElemOff q 1 c <- peekElemOff q 2 d <- peekElemOff q 3 return $ QuadDouble a b c d poke p (QuadDouble a b c d) = do let q = castPtr p pokeElemOff q 0 a pokeElemOff q 1 b pokeElemOff q 2 c pokeElemOff q 3 d lift_qd_qd :: (Ptr CDouble -> Ptr CDouble -> IO ()) -> QuadDouble -> QuadDouble lift_qd_qd f a = unsafePerformIO $ with a $ \p -> alloca $ \r -> f (castPtr p) (castPtr r) >> peek r lift_qd_qd_qd :: (Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> IO ()) -> QuadDouble -> QuadDouble -> QuadDouble lift_qd_qd_qd f a b = unsafePerformIO $ with a $ \p -> with b $ \q -> alloca $ \r -> f (castPtr p) (castPtr q) (castPtr r) >> peek r