module Data.Number.IReal.IntegerInterval where
import Data.Number.IReal.Powers
import Data.Bits
data IntegerInterval = I (Integer, Integer) deriving Show
upto :: Integer -> Integer -> IntegerInterval
l `upto` u = I (l, max u (l+2))
midI, radI, lowerI, upperI :: IntegerInterval -> Integer
midI (I (l,u)) = shift (l+u) (1)
radI (I (l,u)) = shift (ul+1) (1)
lowerI (I (l,_)) = l
upperI (I (_,u)) = u
isThin :: IntegerInterval -> Bool
isThin x = radI x == 1
ivalCase :: IntegerInterval -> a -> a -> a -> a
ivalCase (I (l,u)) pos neg zer
| l >= 0 = pos
| u <= 0 = neg
| otherwise = zer
instance Num IntegerInterval where
I (l1,u1) + I (l2,u2) = I (l1+l2,u1+u2)
i1@(I (l1,u1)) * i2@(I (l2,u2)) =
ivalCase i1
(f (l1*l2,u1*u2) (u1*l2,l1*u2) (u1*l2,u1*u2))
(f (l1*u2,u1*l2) (u1*u2,l1*l2) (l1*u2,l1*l2))
(f (l1*u2,u1*u2) (u1*l2,l1*u2) (min (l1*u2) (u1*l2),max (l1*l2) (u1*u2)))
where f x y z = ivalCase i2 (I x) (I y) (I z)
abs i@(I (l,u)) = ivalCase i i (i) (0 `upto` max (l) u)
negate (I (l,u)) = I (u,l)
signum i = ivalCase i 1 (1) (error "signum (for IntegerInterval): argument includes 0")
fromInteger n = I (n1,n+1)
instance Powers IntegerInterval where
pow i@(I (l,u)) n
|even n = ivalCase i (I (l^n,u^n)) (I (u^n,l^n)) (0 `upto` (max (l) u) ^ n)
|otherwise =I (l^n,u^n)