{-# LANGUAGE ScopedTypeVariables, TypeFamilies, DataKinds, FlexibleContexts, DataKinds, ExistentialQuantification #-} module Data.Sized.Sampled where import Data.Sized.Signed as S import Data.Sized.Matrix as M import Data.Sized.Fin -- A signed fixed precision number, with max value m, via n sampled bits. -- We add an extra bit, to represent the *sign*. data Sampled (m :: Nat) (n :: Nat) = Sampled (Signed n) Rational -- deriving Show toVector :: (SingI m, SingI n) => Sampled m n -> Vector n Bool toVector (Sampled sig _) = S.toVector sig fromVector :: forall n m . (SingI n, SingI m) => Vector n Bool -> Sampled m n fromVector v = mkSampled (fromIntegral scale * fromIntegral val / fromIntegral precision) where val :: Signed n val = S.fromVector v scale :: Integer scale = fromIntegral (fromNat (sing :: Sing m)) precision :: Integer precision = 2 ^ (fromIntegral (fromNat (sing :: Sing n) - 1) :: Integer) mkSampled :: forall n m . (SingI n, SingI m) => Rational -> Sampled m n mkSampled v = Sampled val (fromIntegral scale * fromIntegral val / fromIntegral precision) where scale :: Integer scale = fromIntegral (fromNat (sing :: Sing m)) precision :: Integer precision = 2 ^ (fromIntegral (fromNat (sing :: Sing n) - 1) :: Integer) val0 :: Rational val0 = v / fromIntegral scale val1 :: Integer -- Key rounding step val1 = round (val0 * fromIntegral precision) val = if val1 >= precision then maxBound else if val1 <= -precision then minBound else fromInteger val1 instance (SingI ix) => Eq (Sampled m ix) where (Sampled a _) == (Sampled b _) = a == b instance (SingI ix) => Ord (Sampled m ix) where (Sampled a _) `compare` (Sampled b _) = a `compare` b instance (SingI ix) => Show (Sampled m ix) where show (Sampled _ s) = show (fromRational s :: Double) instance (SingI ix, SingI m) => Read (Sampled m ix) where readsPrec i str = [ (mkSampled a,r) | (a,r) <- readsPrec i str ] instance (SingI ix, SingI m) => Num (Sampled m ix) where (Sampled _ a) + (Sampled _ b) = mkSampled $ a + b (Sampled _ a) - (Sampled _ b) = mkSampled $ a - b (Sampled _ a) * (Sampled _ b) = mkSampled $ a * b abs (Sampled _ n) = mkSampled $ abs n signum (Sampled _ n) = mkSampled $ signum n fromInteger n = mkSampled (fromInteger n) instance (SingI ix, SingI m) => Real (Sampled m ix) where toRational (Sampled _ n) = toRational n instance (SingI ix, SingI m) => Fractional (Sampled m ix) where fromRational n = mkSampled n recip (Sampled _ n) = mkSampled $ recip n -- This is a bit of a hack, and may generate -ve values from fromEnum. instance (SingI ix, SingI m) => Enum (Sampled m ix) where fromEnum (Sampled n _) = fromEnum n toEnum n = mkSampled (fromIntegral scale * fromIntegral val / fromIntegral precision) where val :: Signed ix val = fromIntegral n scale :: Integer scale = fromIntegral (fromNat (sing :: Sing m)) precision :: Integer precision = 2 ^ (fromIntegral (fromNat (sing :: Sing ix) - 1) :: Integer)