packages feed

lhc-0.10: lib/integer-ltm/src/GHC/Integer.hs

module GHC.Integer
    ( Integer
    , toInt#
    , eqInteger
    , neqInteger
    , ltInteger
    , leInteger
    , gtInteger
    , geInteger
    , compareInteger
    , quotRemInteger
    , plusInteger
    , minusInteger
    , timesInteger
    , negateInteger
    , absInteger
    , signumInteger
    , smallInteger
    , quotInteger
    , remInteger
    , divModInteger
    , lcmInteger
    , gcdInteger
    , andInteger
    , orInteger
    , xorInteger
    , complementInteger

#if WORD_SIZE == 4
    , integerToWord64
    , integerToInt64
    , word64ToInteger
    , int64ToInteger
#endif

    , wordToInteger
    , integerToWord
    , floatFromInteger
    , doubleFromInteger
    ) where

import GHC.Types
import GHC.Prim
import GHC.Bool
import GHC.Ordering
import GHC.IntWord64

import GHC.Integer.Ltm
import GHC.Integer.Type

toInt# :: Integer -> Int#
toInt# (Integer a) = mp_get_int a

eqInteger :: Integer -> Integer -> Bool
eqInteger (Integer a) (Integer b) = mp_cmp a b ==# 0#

neqInteger :: Integer -> Integer -> Bool
neqInteger (Integer a) (Integer b) = mp_cmp a b /=# 0#

ltInteger :: Integer -> Integer -> Bool
ltInteger (Integer a) (Integer b) = mp_cmp a b ==# (-1#)

leInteger :: Integer -> Integer -> Bool
leInteger (Integer a) (Integer b) = mp_cmp a b /=# 1#

gtInteger :: Integer -> Integer -> Bool
gtInteger (Integer a) (Integer b) = mp_cmp a b ==# 1#

geInteger :: Integer -> Integer -> Bool
geInteger (Integer a) (Integer b) = mp_cmp a b /=# (-1#)

compareInteger :: Integer -> Integer -> Ordering
compareInteger (Integer a) (Integer b)
    = case mp_cmp a b of
        (-1#) -> LT
        0#    -> EQ
        1#    -> GT

quotRemInteger :: Integer -> Integer -> (# Integer, Integer #)
quotRemInteger a b = (# quotInteger a b, remInteger a b #)

#define BIN_OP(fn) \(Integer a) (Integer b) -> Integer (fn a b)
#define UN_OP(fn) \(Integer a) -> Integer (fn a)

plusInteger :: Integer -> Integer -> Integer
plusInteger = BIN_OP(mp_add)

minusInteger :: Integer -> Integer -> Integer
minusInteger = BIN_OP(mp_sub)

timesInteger :: Integer -> Integer -> Integer
timesInteger = BIN_OP(mp_mul)

negateInteger :: Integer -> Integer
negateInteger = UN_OP(mp_negate)

absInteger :: Integer -> Integer
absInteger = UN_OP(mp_abs)

signumInteger :: Integer -> Integer
signumInteger i = case compareInteger i (smallInteger 0#) of
                    LT -> smallInteger (-1#)
                    EQ -> smallInteger (0#)
                    GT -> smallInteger (1#)

smallInteger :: Int# -> Integer
smallInteger val = Integer (mp_from_int val)

quotInteger :: Integer -> Integer -> Integer
quotInteger = BIN_OP(mp_quot)

remInteger :: Integer -> Integer -> Integer
remInteger = BIN_OP(mp_rem)

divModInteger :: Integer -> Integer -> (# Integer, Integer #)
divModInteger a b = (# divInteger a b, modInteger a b #)

lcmInteger :: Integer -> Integer -> Integer
lcmInteger = BIN_OP(mp_lcm)

gcdInteger :: Integer -> Integer -> Integer
gcdInteger = BIN_OP(mp_gcd)

andInteger :: Integer -> Integer -> Integer
andInteger = BIN_OP(mp_and)

orInteger :: Integer -> Integer -> Integer
orInteger = BIN_OP(mp_or)

xorInteger :: Integer -> Integer -> Integer
xorInteger = BIN_OP(mp_xor)

complementInteger :: Integer -> Integer
complementInteger i = negateInteger i `minusInteger` smallInteger 1#


#if WORD_SIZE == 4
integerToWord64 :: Integer -> Word64#
integerToWord64 = integerToWord64

integerToInt64 :: Integer -> Int64#
integerToInt64 = integerToInt64

word64ToInteger :: Word64# -> Integer
word64ToInteger = word64ToInteger

int64ToInteger :: Int64# -> Integer
int64ToInteger = int64ToInteger
#endif


wordToInteger :: Word# -> Integer
wordToInteger w = smallInteger (word2Int# w)

integerToWord :: Integer -> Word#
integerToWord i = int2Word# (toInt# i)

floatFromInteger :: Integer -> Float#
floatFromInteger i = int2Float# (toInt# i)

doubleFromInteger :: Integer -> Double#
doubleFromInteger i = int2Double# (toInt# i)

divInteger :: Integer -> Integer -> Integer
x `divInteger` y
        -- Be careful NOT to overflow if we do any additional arithmetic
        -- on the arguments...  the following  previous version of this
        -- code has problems with overflow:
--    | (x# ># 0#) && (y# <# 0#) = ((x# -# y#) -# 1#) `quotInt#` y#
--    | (x# <# 0#) && (y# ># 0#) = ((x# -# y#) +# 1#) `quotInt#` y#
    = if (x `gtInteger` smallInteger 0#) && (y `ltInteger` smallInteger 0#)
      then ((x `minusInteger` smallInteger 1#) `quotInteger` y) `minusInteger` smallInteger 1#
      else if (x `ltInteger` smallInteger 0#) && (y `gtInteger` smallInteger 0#)
           then ((x `plusInteger` smallInteger 1#) `quotInteger` y) `minusInteger` smallInteger 1#
           else x `quotInteger` y

modInteger :: Integer -> Integer -> Integer
x `modInteger` y
    = if (x `gtInteger` smallInteger 0#) && (y `ltInteger` smallInteger 0#) ||
         (x `ltInteger` smallInteger 0#) && (y `gtInteger` smallInteger 0#)
      then if r `neqInteger` smallInteger 0# then r `plusInteger` y else smallInteger 0#
      else r
    where
    r = x `remInteger` y

True && True = True
_    && _    = False
otherwise = True
False || False = False
_     || _     = True