88b2e1a063de2ec3f1e2407449408622125bb228
[packages/base.git] / Numeric.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE NoImplicitPrelude, MagicHash #-}
3
4 -----------------------------------------------------------------------------
5 -- |
6 -- Module : Numeric
7 -- Copyright : (c) The University of Glasgow 2002
8 -- License : BSD-style (see the file libraries/base/LICENSE)
9 --
10 -- Maintainer : libraries@haskell.org
11 -- Stability : provisional
12 -- Portability : portable
13 --
14 -- Odds and ends, mostly functions for reading and showing
15 -- 'RealFloat'-like kind of values.
16 --
17 -----------------------------------------------------------------------------
18
19 module Numeric (
20
21 -- * Showing
22
23 showSigned,
24
25 showIntAtBase,
26 showInt,
27 showHex,
28 showOct,
29
30 showEFloat,
31 showFFloat,
32 showGFloat,
33 showFFloatAlt,
34 showGFloatAlt,
35 showFloat,
36
37 floatToDigits,
38
39 -- * Reading
40
41 -- | /NB:/ 'readInt' is the \'dual\' of 'showIntAtBase',
42 -- and 'readDec' is the \`dual\' of 'showInt'.
43 -- The inconsistent naming is a historical accident.
44
45 readSigned,
46
47 readInt,
48 readDec,
49 readOct,
50 readHex,
51
52 readFloat,
53
54 lexDigits,
55
56 -- * Miscellaneous
57
58 fromRat,
59
60 ) where
61
62 import GHC.Base
63 import GHC.Read
64 import GHC.Real
65 import GHC.Float
66 import GHC.Num
67 import GHC.Show
68 import Data.Maybe
69 import Text.ParserCombinators.ReadP( ReadP, readP_to_S, pfail )
70 import qualified Text.Read.Lex as L
71
72 -- -----------------------------------------------------------------------------
73 -- Reading
74
75 -- | Reads an /unsigned/ 'Integral' value in an arbitrary base.
76 readInt :: Num a
77 => a -- ^ the base
78 -> (Char -> Bool) -- ^ a predicate distinguishing valid digits in this base
79 -> (Char -> Int) -- ^ a function converting a valid digit character to an 'Int'
80 -> ReadS a
81 readInt base isDigit valDigit = readP_to_S (L.readIntP base isDigit valDigit)
82
83 -- | Read an unsigned number in octal notation.
84 readOct :: (Eq a, Num a) => ReadS a
85 readOct = readP_to_S L.readOctP
86
87 -- | Read an unsigned number in decimal notation.
88 readDec :: (Eq a, Num a) => ReadS a
89 readDec = readP_to_S L.readDecP
90
91 -- | Read an unsigned number in hexadecimal notation.
92 -- Both upper or lower case letters are allowed.
93 readHex :: (Eq a, Num a) => ReadS a
94 readHex = readP_to_S L.readHexP
95
96 -- | Reads an /unsigned/ 'RealFrac' value,
97 -- expressed in decimal scientific notation.
98 readFloat :: RealFrac a => ReadS a
99 readFloat = readP_to_S readFloatP
100
101 readFloatP :: RealFrac a => ReadP a
102 readFloatP =
103 do tok <- L.lex
104 case tok of
105 L.Number n -> return $ fromRational $ L.numberToRational n
106 _ -> pfail
107
108 -- It's turgid to have readSigned work using list comprehensions,
109 -- but it's specified as a ReadS to ReadS transformer
110 -- With a bit of luck no one will use it.
111
112 -- | Reads a /signed/ 'Real' value, given a reader for an unsigned value.
113 readSigned :: (Real a) => ReadS a -> ReadS a
114 readSigned readPos = readParen False read'
115 where read' r = read'' r ++
116 (do
117 ("-",s) <- lex r
118 (x,t) <- read'' s
119 return (-x,t))
120 read'' r = do
121 (str,s) <- lex r
122 (n,"") <- readPos str
123 return (n,s)
124
125 -- -----------------------------------------------------------------------------
126 -- Showing
127
128 -- | Show /non-negative/ 'Integral' numbers in base 10.
129 showInt :: Integral a => a -> ShowS
130 showInt n0 cs0
131 | n0 < 0 = error "Numeric.showInt: can't show negative numbers"
132 | otherwise = go n0 cs0
133 where
134 go n cs
135 | n < 10 = case unsafeChr (ord '0' + fromIntegral n) of
136 c@(C# _) -> c:cs
137 | otherwise = case unsafeChr (ord '0' + fromIntegral r) of
138 c@(C# _) -> go q (c:cs)
139 where
140 (q,r) = n `quotRem` 10
141
142 -- Controlling the format and precision of floats. The code that
143 -- implements the formatting itself is in @PrelNum@ to avoid
144 -- mutual module deps.
145
146 {-# SPECIALIZE showEFloat ::
147 Maybe Int -> Float -> ShowS,
148 Maybe Int -> Double -> ShowS #-}
149 {-# SPECIALIZE showFFloat ::
150 Maybe Int -> Float -> ShowS,
151 Maybe Int -> Double -> ShowS #-}
152 {-# SPECIALIZE showGFloat ::
153 Maybe Int -> Float -> ShowS,
154 Maybe Int -> Double -> ShowS #-}
155
156 -- | Show a signed 'RealFloat' value
157 -- using scientific (exponential) notation (e.g. @2.45e2@, @1.5e-3@).
158 --
159 -- In the call @'showEFloat' digs val@, if @digs@ is 'Nothing',
160 -- the value is shown to full precision; if @digs@ is @'Just' d@,
161 -- then at most @d@ digits after the decimal point are shown.
162 showEFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
163
164 -- | Show a signed 'RealFloat' value
165 -- using standard decimal notation (e.g. @245000@, @0.0015@).
166 --
167 -- In the call @'showFFloat' digs val@, if @digs@ is 'Nothing',
168 -- the value is shown to full precision; if @digs@ is @'Just' d@,
169 -- then at most @d@ digits after the decimal point are shown.
170 showFFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
171
172 -- | Show a signed 'RealFloat' value
173 -- using standard decimal notation for arguments whose absolute value lies
174 -- between @0.1@ and @9,999,999@, and scientific notation otherwise.
175 --
176 -- In the call @'showGFloat' digs val@, if @digs@ is 'Nothing',
177 -- the value is shown to full precision; if @digs@ is @'Just' d@,
178 -- then at most @d@ digits after the decimal point are shown.
179 showGFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
180
181 showEFloat d x = showString (formatRealFloat FFExponent d x)
182 showFFloat d x = showString (formatRealFloat FFFixed d x)
183 showGFloat d x = showString (formatRealFloat FFGeneric d x)
184
185 -- | Show a signed 'RealFloat' value
186 -- using standard decimal notation (e.g. @245000@, @0.0015@).
187 --
188 -- This behaves as 'showFFloat', except that a decimal point
189 -- is always guaranteed, even if not needed.
190 showFFloatAlt :: (RealFloat a) => Maybe Int -> a -> ShowS
191
192 -- | Show a signed 'RealFloat' value
193 -- using standard decimal notation for arguments whose absolute value lies
194 -- between @0.1@ and @9,999,999@, and scientific notation otherwise.
195 --
196 -- This behaves as 'showFFloat', except that a decimal point
197 -- is always guaranteed, even if not needed.
198 showGFloatAlt :: (RealFloat a) => Maybe Int -> a -> ShowS
199
200 showFFloatAlt d x = showString (formatRealFloatAlt FFFixed d True x)
201 showGFloatAlt d x = showString (formatRealFloatAlt FFGeneric d True x)
202
203 -- ---------------------------------------------------------------------------
204 -- Integer printing functions
205
206 -- | Shows a /non-negative/ 'Integral' number using the base specified by the
207 -- first argument, and the character representation specified by the second.
208 showIntAtBase :: (Integral a, Show a) => a -> (Int -> Char) -> a -> ShowS
209 showIntAtBase base toChr n0 r0
210 | base <= 1 = error ("Numeric.showIntAtBase: applied to unsupported base " ++ show base)
211 | n0 < 0 = error ("Numeric.showIntAtBase: applied to negative number " ++ show n0)
212 | otherwise = showIt (quotRem n0 base) r0
213 where
214 showIt (n,d) r = seq c $ -- stricter than necessary
215 case n of
216 0 -> r'
217 _ -> showIt (quotRem n base) r'
218 where
219 c = toChr (fromIntegral d)
220 r' = c : r
221
222 -- | Show /non-negative/ 'Integral' numbers in base 16.
223 showHex :: (Integral a,Show a) => a -> ShowS
224 showHex = showIntAtBase 16 intToDigit
225
226 -- | Show /non-negative/ 'Integral' numbers in base 8.
227 showOct :: (Integral a, Show a) => a -> ShowS
228 showOct = showIntAtBase 8 intToDigit