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