14e5f65b59c7fdd76c5867df832a7735b237ddfb
[ghc-base.git] / Data / Ratio.hs
1 -----------------------------------------------------------------------------
2 -- |
3 -- Module      :  Data.Ratio
4 -- Copyright   :  (c) The University of Glasgow 2001
5 -- License     :  BSD-style (see the file libraries/base/LICENSE)
6 -- 
7 -- Maintainer  :  libraries@haskell.org
8 -- Stability   :  provisional
9 -- Portability :  portable
10 --
11 -- Standard functions on rational numbers
12 --
13 -----------------------------------------------------------------------------
14
15 module Data.Ratio
16     ( Ratio
17     , Rational
18     , (%)               -- :: (Integral a) => a -> a -> Ratio a
19     , numerator         -- :: (Integral a) => Ratio a -> a
20     , denominator       -- :: (Integral a) => Ratio a -> a
21     , approxRational    -- :: (RealFrac a) => a -> a -> Rational
22
23     -- Ratio instances: 
24     --   (Integral a) => Eq   (Ratio a)
25     --   (Integral a) => Ord  (Ratio a)
26     --   (Integral a) => Num  (Ratio a)
27     --   (Integral a) => Real (Ratio a)
28     --   (Integral a) => Fractional (Ratio a)
29     --   (Integral a) => RealFrac (Ratio a)
30     --   (Integral a) => Enum     (Ratio a)
31     --   (Read a, Integral a) => Read (Ratio a)
32     --   (Integral a) => Show     (Ratio a)
33
34   ) where
35
36 import Prelude
37
38 #ifdef __GLASGOW_HASKELL__
39 import GHC.Real         -- The basic defns for Ratio
40 #endif
41
42 #ifdef __HUGS__
43 import Hugs.Prelude(Ratio(..), (%), numerator, denominator)
44 #endif
45
46 #ifdef __NHC__
47 import Ratio (Ratio(..), (%), numerator, denominator, approxRational)
48 #else
49
50 -- -----------------------------------------------------------------------------
51 -- approxRational
52
53 -- @approxRational@, applied to two real fractional numbers x and epsilon,
54 -- returns the simplest rational number within epsilon of x.  A rational
55 -- number n%d in reduced form is said to be simpler than another n'%d' if
56 -- abs n <= abs n' && d <= d'.  Any real interval contains a unique
57 -- simplest rational; here, for simplicity, we assume a closed rational
58 -- interval.  If such an interval includes at least one whole number, then
59 -- the simplest rational is the absolutely least whole number.  Otherwise,
60 -- the bounds are of the form q%1 + r%d and q%1 + r'%d', where abs r < d
61 -- and abs r' < d', and the simplest rational is q%1 + the reciprocal of
62 -- the simplest rational between d'%r' and d%r.
63
64 approxRational          :: (RealFrac a) => a -> a -> Rational
65 approxRational rat eps  =  simplest (rat-eps) (rat+eps)
66         where simplest x y | y < x      =  simplest y x
67                            | x == y     =  xr
68                            | x > 0      =  simplest' n d n' d'
69                            | y < 0      =  - simplest' (-n') d' (-n) d
70                            | otherwise  =  0 :% 1
71                                         where xr  = toRational x
72                                               n   = numerator xr
73                                               d   = denominator xr
74                                               nd' = toRational y
75                                               n'  = numerator nd'
76                                               d'  = denominator nd'
77
78               simplest' n d n' d'       -- assumes 0 < n%d < n'%d'
79                         | r == 0     =  q :% 1
80                         | q /= q'    =  (q+1) :% 1
81                         | otherwise  =  (q*n''+d'') :% n''
82                                      where (q,r)      =  quotRem n d
83                                            (q',r')    =  quotRem n' d'
84                                            nd''       =  simplest' d' r' d r
85                                            n''        =  numerator nd''
86                                            d''        =  denominator nd''
87 #endif