module Feldspar.Core.Functions.Integral where
import qualified Prelude
import Data.Int
import Data.Word
import Feldspar.Prelude
import Feldspar.Range
import Feldspar.Core.Types
import Feldspar.Core.Representation
import Feldspar.Core.Constructs
import Feldspar.Core.Functions.Logic
import Feldspar.Core.Functions.Eq
import Feldspar.Core.Functions.Ord
import Feldspar.Core.Functions.Num
import Feldspar.Core.Functions.Bits
class (Numeric a, BoundedInt a, Bits a, Ord a) => Integral a where
quot :: Data a -> Data a -> Data a
quot = defaultQuot
rem :: Data a -> Data a -> Data a
div :: Data a -> Data a -> Data a
div = defaultDiv
mod :: Data a -> Data a -> Data a
mod = defaultMod
(^) :: Data a -> Data a -> Data a
(^) = optExp fullProp
defaultQuot :: Integral a => Data a -> Data a -> Data a
defaultQuot = function2 "quot" fullProp Prelude.quot
optQuot :: (Integral a, BoundedInt a, Size a ~ Range a) =>
Data a -> Data a -> Data a
optQuot x y = function2 "quot" rangeQuot Prelude.quot x y
defaultDiv :: Integral a => Data a -> Data a -> Data a
defaultDiv x y = rem x y /= 0 && (x > 0 && y < 0 || x < 0 && y > 0) ?
(quotxy 1, quotxy)
where
quotxy = quot x y
defaultMod :: Integral a => Data a -> Data a -> Data a
defaultMod x y = remxy /= 0 && (x > 0 && y < 0 || x < 0 && y > 0) ?
(remxy + y, remxy)
where
remxy = rem x y
optRem :: (Integral a, BoundedInt a, Size a ~ Range a) =>
Data a -> Data a -> Data a
optRem x y
| otherwise = function2 "rem" rangeRem Prelude.rem x y
where rx = dataSize x
ry = dataSize y
optMod :: (Integral a, BoundedInt b, Size a ~ Range b) =>
Data a -> Data a -> Data a
optMod x y = cap (rangeMod rx ry) $
remxy /= 0 && (x > 0 && y < 0 || x < 0 && y > 0) ?
(remxy + y, remxy)
where remxy = rem x y
rx = dataSize x
ry = dataSize y
optExp :: Integral a =>
(Size a -> Size a -> Size a)
-> Data a -> Data a -> Data a
optExp prop m e = case (viewLiteral m, viewLiteral e) of
(Just 1,_) -> value 1
(_,Just 1) -> m
(_,Just 0) -> value 1
_ -> function2 "(^)" prop (Prelude.^) m e
optSignedExp :: (Integral a, Signed a, BoundedInt b, Size a ~ Range b) =>
Data a -> Data a -> Data a
optSignedExp m e = case viewLiteral m of
Just (1) -> cap (range (1) 1) $
let isOdd = e .&. 1
in (1 `xor` (negate isOdd)) + isOdd
_ -> optExp rangeExp m e
instance Integral Word8 where
div = optQuot
rem = optRem
mod = rem
instance Integral Int8 where
rem = optRem
mod = optMod
(^) = optSignedExp
instance Integral Word16 where
div = optQuot
rem = optRem
mod = rem
instance Integral Int16 where
rem = optRem
mod = optMod
(^) = optSignedExp
instance Integral Word32 where
div = optQuot
rem = optRem
mod = rem
instance Integral Int32 where
rem = optRem
mod = optMod
(^) = optSignedExp
instance Integral DefaultWord where
div = optQuot
rem = optRem
mod = rem
instance Integral DefaultInt where
rem = optRem
mod = optMod
(^) = optSignedExp