[project @ 2002-01-02 14:40:09 by simonmar]
[ghc-base.git] / Numeric.hs
1 -----------------------------------------------------------------------------
2 -- 
3 -- Module      :  Numeric
4 -- Copyright   :  (c) The University of Glasgow 2001
5 -- License     :  BSD-style (see the file libraries/core/LICENSE)
6 -- 
7 -- Maintainer  :  libraries@haskell.org
8 -- Stability   :  experimental
9 -- Portability :  portable
10 --
11 -- $Id: Numeric.hs,v 1.3 2002/01/02 14:40:09 simonmar Exp $
12 --
13 -- Odds and ends, mostly functions for reading and showing
14 -- RealFloat-like kind of values.
15 --
16 -----------------------------------------------------------------------------
17
18 module Numeric (
19
20         fromRat,          -- :: (RealFloat a) => Rational -> a
21         showSigned,       -- :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
22         readSigned,       -- :: (Real a) => ReadS a -> ReadS a
23         showInt,          -- :: Integral a => a -> ShowS
24         readInt,          -- :: (Integral a) => a -> (Char -> Bool)
25                           --         -> (Char -> Int) -> ReadS a
26         
27         readDec,          -- :: (Integral a) => ReadS a
28         readOct,          -- :: (Integral a) => ReadS a
29         readHex,          -- :: (Integral a) => ReadS a
30
31         showHex,          -- :: Integral a => a -> ShowS
32         showOct,          -- :: Integral a => a -> ShowS
33         showBin,          -- :: Integral a => a -> ShowS
34       
35         showEFloat,       -- :: (RealFloat a) => Maybe Int -> a -> ShowS
36         showFFloat,       -- :: (RealFloat a) => Maybe Int -> a -> ShowS
37         showGFloat,       -- :: (RealFloat a) => Maybe Int -> a -> ShowS
38         showFloat,        -- :: (RealFloat a) => a -> ShowS
39         readFloat,        -- :: (RealFloat a) => ReadS a
40         
41          
42         floatToDigits,    -- :: (RealFloat a) => Integer -> a -> ([Int], Int)
43         lexDigits,        -- :: ReadS String
44
45           -- general purpose number->string converter.
46         showIntAtBase,    -- :: Integral a 
47                           -- => a               -- base
48                           -- -> (a -> Char)      -- digit to char
49                           -- -> a                -- number to show.
50                           -- -> ShowS
51         ) where
52
53 import Prelude          -- For dependencies
54 import Data.Char
55
56 #ifdef __GLASGOW_HASKELL__
57 import GHC.Base         ( Char(..), unsafeChr )
58 import GHC.Read
59 import GHC.Real         ( showSigned )
60 import GHC.Float
61 #endif
62
63 #ifdef __HUGS__
64 import Array
65 #endif
66
67 #ifdef __GLASGOW_HASKELL__
68 showInt :: Integral a => a -> ShowS
69 showInt n cs
70     | n < 0     = error "Numeric.showInt: can't show negative numbers"
71     | otherwise = go n cs
72     where
73     go n cs
74         | n < 10    = case unsafeChr (ord '0' + fromIntegral n) of
75             c@(C# _) -> c:cs
76         | otherwise = case unsafeChr (ord '0' + fromIntegral r) of
77             c@(C# _) -> go q (c:cs)
78         where
79         (q,r) = n `quotRem` 10
80
81 -- Controlling the format and precision of floats. The code that
82 -- implements the formatting itself is in @PrelNum@ to avoid
83 -- mutual module deps.
84
85 {-# SPECIALIZE showEFloat ::
86         Maybe Int -> Float  -> ShowS,
87         Maybe Int -> Double -> ShowS #-}
88 {-# SPECIALIZE showFFloat ::
89         Maybe Int -> Float  -> ShowS,
90         Maybe Int -> Double -> ShowS #-}
91 {-# SPECIALIZE showGFloat ::
92         Maybe Int -> Float  -> ShowS,
93         Maybe Int -> Double -> ShowS #-}
94
95 showEFloat    :: (RealFloat a) => Maybe Int -> a -> ShowS
96 showFFloat    :: (RealFloat a) => Maybe Int -> a -> ShowS
97 showGFloat    :: (RealFloat a) => Maybe Int -> a -> ShowS
98
99 showEFloat d x =  showString (formatRealFloat FFExponent d x)
100 showFFloat d x =  showString (formatRealFloat FFFixed d x)
101 showGFloat d x =  showString (formatRealFloat FFGeneric d x)
102 #endif
103
104 #ifdef __HUGS__
105 -- This converts a rational to a floating.  This should be used in the
106 -- Fractional instances of Float and Double.
107
108 fromRat :: (RealFloat a) => Rational -> a
109 fromRat x = 
110     if x == 0 then encodeFloat 0 0              -- Handle exceptional cases
111     else if x < 0 then - fromRat' (-x)          -- first.
112     else fromRat' x
113
114 -- Conversion process:
115 -- Scale the rational number by the RealFloat base until
116 -- it lies in the range of the mantissa (as used by decodeFloat/encodeFloat).
117 -- Then round the rational to an Integer and encode it with the exponent
118 -- that we got from the scaling.
119 -- To speed up the scaling process we compute the log2 of the number to get
120 -- a first guess of the exponent.
121 fromRat' :: (RealFloat a) => Rational -> a
122 fromRat' x = r
123   where b = floatRadix r
124         p = floatDigits r
125         (minExp0, _) = floatRange r
126         minExp = minExp0 - p            -- the real minimum exponent
127         xMin = toRational (expt b (p-1))
128         xMax = toRational (expt b p)
129         p0 = (integerLogBase b (numerator x) -
130               integerLogBase b (denominator x) - p) `max` minExp
131         f = if p0 < 0 then 1 % expt b (-p0) else expt b p0 % 1
132         (x', p') = scaleRat (toRational b) minExp xMin xMax p0 (x / f)
133         r = encodeFloat (round x') p'
134
135 -- Scale x until xMin <= x < xMax, or p (the exponent) <= minExp.
136 scaleRat :: Rational -> Int -> Rational -> Rational -> 
137              Int -> Rational -> (Rational, Int)
138 scaleRat b minExp xMin xMax p x =
139     if p <= minExp then
140         (x, p)
141     else if x >= xMax then
142         scaleRat b minExp xMin xMax (p+1) (x/b)
143     else if x < xMin  then
144         scaleRat b minExp xMin xMax (p-1) (x*b)
145     else
146         (x, p)
147
148 -- Exponentiation with a cache for the most common numbers.
149 minExpt = 0::Int
150 maxExpt = 1100::Int
151 expt :: Integer -> Int -> Integer
152 expt base n =
153     if base == 2 && n >= minExpt && n <= maxExpt then
154         expts!n
155     else
156         base^n
157
158 expts :: Array Int Integer
159 expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]
160
161 -- Compute the (floor of the) log of i in base b.
162 -- Simplest way would be just divide i by b until it's smaller then b,
163 -- but that would be very slow!  We are just slightly more clever.
164 integerLogBase :: Integer -> Integer -> Int
165 integerLogBase b i =
166      if i < b then
167         0
168      else
169         -- Try squaring the base first to cut down the number of divisions.
170         let l = 2 * integerLogBase (b*b) i
171             doDiv :: Integer -> Int -> Int
172             doDiv i l = if i < b then l else doDiv (i `div` b) (l+1)
173         in  doDiv (i `div` (b^l)) l
174
175
176 -- Misc utilities to show integers and floats 
177
178 showEFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
179 showFFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
180 showGFloat     :: (RealFloat a) => Maybe Int -> a -> ShowS
181 showFloat      :: (RealFloat a) => a -> ShowS
182
183 showEFloat d x =  showString (formatRealFloat FFExponent d x)
184 showFFloat d x =  showString (formatRealFloat FFFixed d x)
185 showGFloat d x =  showString (formatRealFloat FFGeneric d x)
186 showFloat      =  showGFloat Nothing 
187
188 -- These are the format types.  This type is not exported.
189
190 data FFFormat = FFExponent | FFFixed | FFGeneric
191
192 formatRealFloat :: (RealFloat a) => FFFormat -> Maybe Int -> a -> String
193 formatRealFloat fmt decs x = s
194   where base = 10
195         s = if isNaN x then 
196                 "NaN"
197             else if isInfinite x then 
198                 if x < 0 then "-Infinity" else "Infinity"
199             else if x < 0 || isNegativeZero x then 
200                 '-' : doFmt fmt (floatToDigits (toInteger base) (-x))
201             else 
202                 doFmt fmt (floatToDigits (toInteger base) x)
203         doFmt fmt (is, e) =
204             let ds = map intToDigit is
205             in  case fmt of
206                 FFGeneric -> 
207                     doFmt (if e < 0 || e > 7 then FFExponent else FFFixed)
208                           (is, e)
209                 FFExponent ->
210                     case decs of
211                     Nothing ->
212                         case ds of
213                          ['0'] -> "0.0e0"
214                          [d]   -> d : ".0e" ++ show (e-1)
215                          d:ds  -> d : '.' : ds ++ 'e':show (e-1)
216                     Just dec ->
217                         let dec' = max dec 1 in
218                         case is of
219                          [0] -> '0':'.':take dec' (repeat '0') ++ "e0"
220                          _ ->
221                           let (ei, is') = roundTo base (dec'+1) is
222                               d:ds = map intToDigit
223                                          (if ei > 0 then init is' else is')
224                           in d:'.':ds  ++ "e" ++ show (e-1+ei)
225                 FFFixed ->
226                     case decs of
227                     Nothing ->
228                         let f 0 s ds = mk0 s ++ "." ++ mk0 ds
229                             f n s "" = f (n-1) (s++"0") ""
230                             f n s (d:ds) = f (n-1) (s++[d]) ds
231                             mk0 "" = "0"
232                             mk0 s = s
233                         in  f e "" ds
234                     Just dec ->
235                         let dec' = max dec 0 in
236                         if e >= 0 then
237                             let (ei, is') = roundTo base (dec' + e) is
238                                 (ls, rs) = splitAt (e+ei) (map intToDigit is')
239                             in  (if null ls then "0" else ls) ++ 
240                                 (if null rs then "" else '.' : rs)
241                         else
242                             let (ei, is') = roundTo base dec'
243                                               (replicate (-e) 0 ++ is)
244                                 d : ds = map intToDigit
245                                             (if ei > 0 then is' else 0:is')
246                             in  d : '.' : ds
247
248 roundTo :: Int -> Int -> [Int] -> (Int, [Int])
249 roundTo base d is = case f d is of
250                 (0, is) -> (0, is)
251                 (1, is) -> (1, 1 : is)
252   where b2 = base `div` 2
253         f n [] = (0, replicate n 0)
254         f 0 (i:_) = (if i >= b2 then 1 else 0, [])
255         f d (i:is) = 
256             let (c, ds) = f (d-1) is
257                 i' = c + i
258             in  if i' == base then (1, 0:ds) else (0, i':ds)
259
260 --
261 -- Based on "Printing Floating-Point Numbers Quickly and Accurately"
262 -- by R.G. Burger and R. K. Dybvig, in PLDI 96.
263 -- This version uses a much slower logarithm estimator.  It should be improved.
264
265 -- This function returns a list of digits (Ints in [0..base-1]) and an
266 -- exponent.
267
268 floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
269
270 floatToDigits _ 0 = ([0], 0)
271 floatToDigits base x =
272     let (f0, e0) = decodeFloat x
273         (minExp0, _) = floatRange x
274         p = floatDigits x
275         b = floatRadix x
276         minExp = minExp0 - p            -- the real minimum exponent
277         -- Haskell requires that f be adjusted so denormalized numbers
278         -- will have an impossibly low exponent.  Adjust for this.
279         (f, e) = let n = minExp - e0
280                  in  if n > 0 then (f0 `div` (b^n), e0+n) else (f0, e0)
281
282         (r, s, mUp, mDn) =
283            if e >= 0 then
284                let be = b^e in
285                if f == b^(p-1) then
286                    (f*be*b*2, 2*b, be*b, b)
287                else
288                    (f*be*2, 2, be, be)
289            else
290                if e > minExp && f == b^(p-1) then
291                    (f*b*2, b^(-e+1)*2, b, 1)
292                else
293                    (f*2, b^(-e)*2, 1, 1)
294         k = 
295             let k0 =
296                     if b==2 && base==10 then
297                         -- logBase 10 2 is slightly bigger than 3/10 so
298                         -- the following will err on the low side.  Ignoring
299                         -- the fraction will make it err even more.
300                         -- Haskell promises that p-1 <= logBase b f < p.
301                         (p - 1 + e0) * 3 `div` 10
302                     else
303                         ceiling ((log (fromInteger (f+1)) + 
304                                  fromIntegral e * log (fromInteger b)) / 
305                                   log (fromInteger base))
306                 fixup n =
307                     if n >= 0 then
308                         if r + mUp <= expt base n * s then n else fixup (n+1)
309                     else
310                         if expt base (-n) * (r + mUp) <= s then n
311                                                            else fixup (n+1)
312             in  fixup k0
313
314         gen ds rn sN mUpN mDnN =
315             let (dn, rn') = (rn * base) `divMod` sN
316                 mUpN' = mUpN * base
317                 mDnN' = mDnN * base
318             in  case (rn' < mDnN', rn' + mUpN' > sN) of
319                 (True,  False) -> dn : ds
320                 (False, True)  -> dn+1 : ds
321                 (True,  True)  -> if rn' * 2 < sN then dn : ds else dn+1 : ds
322                 (False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'
323         rds =
324             if k >= 0 then
325                 gen [] r (s * expt base k) mUp mDn
326             else
327                 let bk = expt base (-k)
328                 in  gen [] (r * bk) s (mUp * bk) (mDn * bk)
329     in  (map fromIntegral (reverse rds), k)
330 #endif
331
332 -- ---------------------------------------------------------------------------
333 -- Integer printing functions
334
335 showIntAtBase :: Integral a => a -> (a -> Char) -> a -> ShowS
336 showIntAtBase base toChr n r
337   | n < 0  = error ("Numeric.showIntAtBase: applied to negative number " ++ show n)
338   | otherwise = 
339     case quotRem n base of { (n', d) ->
340     let c = toChr d in
341     seq c $ -- stricter than necessary
342     let
343         r' = c : r
344     in
345     if n' == 0 then r' else showIntAtBase base toChr n' r'
346     }
347
348 showHex :: Integral a => a -> ShowS
349 showHex n r = 
350  showString "0x" $
351  showIntAtBase 16 (toChrHex) n r
352  where  
353   toChrHex d
354     | d < 10    = chr (ord '0' + fromIntegral d)
355     | otherwise = chr (ord 'a' + fromIntegral (d - 10))
356
357 showOct :: Integral a => a -> ShowS
358 showOct n r = 
359  showString "0o" $
360  showIntAtBase 8 (toChrOct) n r
361  where toChrOct d = chr (ord '0' + fromIntegral d)
362
363 showBin :: Integral a => a -> ShowS
364 showBin n r = 
365  showString "0b" $
366  showIntAtBase 2 (toChrOct) n r
367  where toChrOct d = chr (ord '0' + fromIntegral d)