module Fractal.RUFF.Types.Ratio
( Q(..)
, Ratio(..)
, Rational
) where
import Data.Data (Data)
import Data.Typeable (Typeable)
import Prelude hiding (Rational)
import qualified Data.Ratio as Ratio
class Q r where
type Z r
infixl 7 %, %!
(%) :: Z r -> Z r -> r
numerator :: r -> Z r
denominator :: r -> Z r
(%!) :: Z r -> Z r -> r
(%!) = (%)
zero :: Integral (Z r) => r
zero = 0 %! 1
half :: Integral (Z r) => r
half = 1 %! 2
one :: Integral (Z r) => r
one = 1 %! 1
fromQ :: Integral (Z r) => r -> Ratio.Rational
fromQ x = toInteger (numerator x) %! toInteger (denominator x)
toQ :: Integral (Z r) => Ratio.Rational -> r
toQ x = fromInteger (Ratio.numerator x) %! fromInteger (Ratio.denominator x)
wrap :: Integral (Z r) => r -> r
wrap x = (numerator x `mod` denominator x) %! denominator x
doubleWrap :: Integral (Z r) => r -> r
doubleWrap = double . wrap
double :: Integral (Z r) => r -> r
double x = case () of
_| even d -> (if n < d' then n else n d') % d'
| otherwise -> (if n' < d then n' else n' d) %! d
where
d = denominator x
d' = d `div` 2
n = numerator x
n' = 2 * n
doubleOdd :: Integral (Z r) => r -> r
doubleOdd x = (if n' < d then n' else n' d) %! d
where
d = denominator x
n = numerator x
n' = 2 * n
preimages :: Integral (Z r) => r -> (r, r)
preimages x = (n % d', (n + d) % d')
where
n = numerator x
d = denominator x
d' = 2 * d
instance Integral a => Q (Ratio.Ratio a) where
type Z (Ratio.Ratio a) = a
(%) = (Ratio.%)
numerator = Ratio.numerator
denominator = Ratio.denominator
data Ratio a = !a :% !a deriving (Eq, Data, Typeable)
type Rational = Ratio Integer
instance Integral a => Q (Ratio a) where
type Z (Ratio a) = a
x % y = reduce (x * signum y) (abs y)
where reduce x' y' = (x' `quot` d) :% (y' `quot` d) where d = gcd x' y'
x %! y = x :% y
numerator (x :% _) = x
denominator (_ :% y) = y
instance Integral a => Ord (Ratio a) where
(x:%y) <= (x':%y') = x * y' <= x' * y
(x:%y) < (x':%y') = x * y' < x' * y
instance (Integral a, Read a) => Read (Ratio a) where
readsPrec p = map (\(x,y) -> (toQ x, y)) . readsPrec p
instance (Integral a, Show a) => Show (Ratio a) where
showsPrec p = showsPrec p . fromQ