17337f590a66fe64e08359cb62ddbc4c996d310c
[packages/haskell2010.git] / Data / Ratio.hs
1 #if __GLASGOW_HASKELL__ >= 701
2 {-# LANGUAGE Safe #-}
3 #endif
4
5 module Data.Ratio (
6 Ratio
7 , Rational
8 , (%) -- :: (Integral a) => a -> a -> Ratio a
9 , numerator -- :: (Integral a) => Ratio a -> a
10 , denominator -- :: (Integral a) => Ratio a -> a
11 , approxRational -- :: (RealFrac a) => a -> a -> Rational
12
13 -- * Specification
14
15 -- $code
16 ) where
17 import "base" Data.Ratio
18
19 {- $code
20 > module Data.Ratio (
21 > Ratio, Rational, (%), numerator, denominator, approxRational ) where
22 >
23 > infixl 7 %
24 >
25 > ratPrec = 7 :: Int
26 >
27 > data (Integral a) => Ratio a = !a :% !a deriving (Eq)
28 > type Rational = Ratio Integer
29 >
30 > (%) :: (Integral a) => a -> a -> Ratio a
31 > numerator, denominator :: (Integral a) => Ratio a -> a
32 > approxRational :: (RealFrac a) => a -> a -> Rational
33 >
34 >
35 > -- "reduce" is a subsidiary function used only in this module.
36 > -- It normalises a ratio by dividing both numerator
37 > -- and denominator by their greatest common divisor.
38 > --
39 > -- E.g., 12 `reduce` 8 == 3 :% 2
40 > -- 12 `reduce` (-8) == 3 :% (-2)
41 >
42 > reduce _ 0 = error "Data.Ratio.% : zero denominator"
43 > reduce x y = (x `quot` d) :% (y `quot` d)
44 > where d = gcd x y
45 >
46 > x % y = reduce (x * signum y) (abs y)
47 >
48 > numerator (x :% _) = x
49 >
50 > denominator (_ :% y) = y
51 >
52 >
53 > instance (Integral a) => Ord (Ratio a) where
54 > (x:%y) <= (x':%y') = x * y' <= x' * y
55 > (x:%y) < (x':%y') = x * y' < x' * y
56 >
57 > instance (Integral a) => Num (Ratio a) where
58 > (x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y')
59 > (x:%y) * (x':%y') = reduce (x * x') (y * y')
60 > negate (x:%y) = (-x) :% y
61 > abs (x:%y) = abs x :% y
62 > signum (x:%y) = signum x :% 1
63 > fromInteger x = fromInteger x :% 1
64 >
65 > instance (Integral a) => Real (Ratio a) where
66 > toRational (x:%y) = toInteger x :% toInteger y
67 >
68 > instance (Integral a) => Fractional (Ratio a) where
69 > (x:%y) / (x':%y') = (x*y') % (y*x')
70 > recip (x:%y) = y % x
71 > fromRational (x:%y) = fromInteger x :% fromInteger y
72 >
73 > instance (Integral a) => RealFrac (Ratio a) where
74 > properFraction (x:%y) = (fromIntegral q, r:%y)
75 > where (q,r) = quotRem x y
76 >
77 > instance (Integral a) => Enum (Ratio a) where
78 > succ x = x+1
79 > pred x = x-1
80 > toEnum = fromIntegral
81 > fromEnum = fromInteger . truncate -- May overflow
82 > enumFrom = numericEnumFrom -- These numericEnumXXX functions
83 > enumFromThen = numericEnumFromThen -- are as defined in Prelude.hs
84 > enumFromTo = numericEnumFromTo -- but not exported from it!
85 > enumFromThenTo = numericEnumFromThenTo
86 >
87 > instance (Read a, Integral a) => Read (Ratio a) where
88 > readsPrec p = readParen (p > ratPrec)
89 > (\r -> [(x%y,u) | (x,s) <- readsPrec (ratPrec+1) r,
90 > ("%",t) <- lex s,
91 > (y,u) <- readsPrec (ratPrec+1) t ])
92 >
93 > instance (Integral a) => Show (Ratio a) where
94 > showsPrec p (x:%y) = showParen (p > ratPrec)
95 > showsPrec (ratPrec+1) x .
96 > showString " % " .
97 > showsPrec (ratPrec+1) y)
98 >
99 >
100 >
101 > approxRational x eps = simplest (x-eps) (x+eps)
102 > where simplest x y | y < x = simplest y x
103 > | x == y = xr
104 > | x > 0 = simplest' n d n' d'
105 > | y < 0 = - simplest' (-n') d' (-n) d
106 > | otherwise = 0 :% 1
107 > where xr@(n:%d) = toRational x
108 > (n':%d') = toRational y
109 >
110 > simplest' n d n' d' -- assumes 0 < n%d < n'%d'
111 > | r == 0 = q :% 1
112 > | q /= q' = (q+1) :% 1
113 > | otherwise = (q*n''+d'') :% n''
114 > where (q,r) = quotRem n d
115 > (q',r') = quotRem n' d'
116 > (n'':%d'') = simplest' d' r' d r
117 -}