{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Boopadoop.Discrete where
import Data.Int
import Data.Bits
newtype Discrete = Discrete {unDiscrete :: Int32} deriving (Eq,Ord)
instance Show Discrete where
show (Discrete x) = "Discrete {unDiscrete = " ++ show x ++ ", value = " ++ show (fromIntegral x / discFactor :: Double) ++ "}"
doubleToDiscrete :: Double -> Discrete
doubleToDiscrete x = Discrete . properFloor $ x * discFactor
discreteToDouble :: Discrete -> Double
discreteToDouble (Discrete x) = fromIntegral x / discFactor
discFactor :: Num a => a
discFactor = fromIntegral $ (maxBound :: Int32)
properFloor :: RealFrac a => a -> Int32
properFloor x = if x >= 0 then floor x else ceiling x
instance Num Discrete where
(Discrete a) + (Discrete b) = Discrete $ let s = a + b in if signum a == signum b && signum a /= signum s then error ("Discrete overflow! " ++ show (Discrete a) ++ " + " ++ show (Discrete b) ++ " /= " ++ show (Discrete s)) else s
a - b = a + negate b
(*) = multiplyDiscrete
negate (Discrete a) = Discrete (negate a)
abs (Discrete a) = Discrete (abs a)
signum (Discrete a) = Discrete (signum a)
fromInteger i = if i `elem` [-1,0,1]
then Discrete $ discFactor * (fromInteger i :: Int32)
else error $ "(fromInteger " ++ show i ++ " :: Discrete)"
multiplyDiscrete :: Discrete -> Discrete -> Discrete
multiplyDiscrete (Discrete a) (Discrete b) = let m = Discrete . fromIntegral $ ((fromIntegral a :: Int64) * (fromIntegral b :: Int64)) `div` (discFactor + 1) in if signum m /= 0 && signum a * signum b /= signum (unDiscrete m) then error ("Discrete multiply overflow!! " ++ show (Discrete a) ++ " * " ++ show (Discrete b) ++ " /= " ++ show m) else m
instance Fractional Discrete where
(Discrete a) / (Discrete b) = let d = Discrete . fromIntegral $ ((fromIntegral a :: Int64) * (discFactor + 1)) `div` fromIntegral b in if signum d /= 0 && signum a * signum b /= signum (unDiscrete d) then error ("Discrete division overflow!! " ++ show (Discrete a) ++ " / " ++ show (Discrete b) ++ " /= " ++ show d) else d
fromRational r = if r <= 1 && r >= -1
then Discrete . properFloor $ discFactor * r
else error $ "(fromRational " ++ show r ++ " :: Discrete)"
instance Bounded Discrete where
minBound = -1
maxBound = 1
disguise :: (Double -> Double) -> Discrete -> Discrete
disguise f (Discrete x) = Discrete . properFloor $ f (fromIntegral x / discFactor :: Double) * discFactor
newtype Tick = Tick {unTick :: Int32} deriving (Enum,Num,Ord,Eq,Real,Integral)
instance Show Tick where
show (Tick a) = "Tick[" ++ show a ++ "]"