X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Flib%2Fghc%2FPrelNum.lhs;h=e329d74ba57bd5b1a9a5cd5f15c0f14ff7866b35;hb=848705ff3958b140cde0f7883fba62f540ea3542;hp=940a57b73a9cf6623a74f12bc4ef62d4d6873464;hpb=8de16184643ea3c2f9f30b5eaed18db6ef247760;p=ghc-hetmet.git diff --git a/ghc/lib/ghc/PrelNum.lhs b/ghc/lib/ghc/PrelNum.lhs index 940a57b..e329d74 100644 --- a/ghc/lib/ghc/PrelNum.lhs +++ b/ghc/lib/ghc/PrelNum.lhs @@ -9,19 +9,27 @@ Numeric part of the prelude. It's rather big! \begin{code} +{-# OPTIONS -fno-implicit-prelude -#include "cbits/floatExtreme.h" #-} {-# OPTIONS -H20m #-} + #include "../includes/ieee-flpt.h" + \end{code} \begin{code} -{-# OPTIONS -fno-implicit-prelude #-} - module PrelNum where -import {-# SOURCE #-} IOBase ( error ) -import PrelList import PrelBase import GHC +import {-# SOURCE #-} IOBase ( error ) +import PrelList + +import ArrBase ( Array, array, (!) ) +import STBase ( unsafePerformPrimIO ) +import Ix ( Ix(..) ) +import Foreign () -- This import tells the dependency analyser to compile Foreign first. + -- There's an implicit dependency on Foreign because the ccalls in + -- PrelNum implicitly mention CCallable. infixr 8 ^, ^^, ** infixl 7 /, %, `quot`, `rem`, `div`, `mod` @@ -327,6 +335,8 @@ instance Integral Integer where -- Case-ified by WDP 94/10 instance Enum Integer where + toEnum n = toInteger n + fromEnum n = toInt n enumFrom n = n : enumFrom (n + 1) enumFromThen m n = en' m (n - m) where en' m n = m : en' (m + n) n @@ -338,8 +348,18 @@ instance Show Integer where showsPrec x = showSignedInteger x showList = showList__ (showsPrec 0) +instance Ix Integer where + range (m,n) = [m..n] + index b@(m,n) i + | inRange b i = fromInteger (i - m) + | otherwise = error "Integer.index: Index out of range." + inRange (m,n) i = m <= i && i <= n + integer_0, integer_1, integer_2, integer_m1 :: Integer -integer_0 = 0; integer_1 = 1; integer_2 = 2; integer_m1 = -1 +integer_0 = int2Integer# 0# +integer_1 = int2Integer# 1# +integer_2 = int2Integer# 2# +integer_m1 = int2Integer# (negateInt# 1#) \end{code} @@ -361,7 +381,7 @@ instance Ord Float where (F# x) < (F# y) = x `ltFloat#` y (F# x) <= (F# y) = x `leFloat#` y (F# x) >= (F# y) = x `geFloat#` y - (F# x) > (F# y) = x `geFloat#` y + (F# x) > (F# y) = x `gtFloat#` y instance Num Float where (+) x y = plusFloat x y @@ -383,7 +403,7 @@ instance Real Float where instance Fractional Float where (/) x y = divideFloat x y - fromRational x = fromRational__ x + fromRational x = fromRat x recip x = 1.0 / x instance Floating Float where @@ -472,6 +492,15 @@ instance RealFloat Float where scaleFloat k x = case decodeFloat x of (m,n) -> encodeFloat m (n+k) + isNaN x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isFloatNaN x) {- a _pure_function! -} + isInfinite x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isFloatInfinite x) {- ditto! -} + isDenormalized x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isFloatDenormalized x) -- .. + isNegativeZero x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isFloatNegativeZero x) -- ... + isIEEE x = True instance Show Float where showsPrec x = showSigned showFloat x @@ -518,7 +547,7 @@ instance Real Double where instance Fractional Double where (/) x y = divideDouble x y - fromRational x = fromRational__ x + fromRational x = fromRat x recip x = 1.0 / x instance Floating Double where @@ -615,6 +644,15 @@ instance RealFloat Double where scaleFloat k x = case decodeFloat x of (m,n) -> encodeFloat m (n+k) + isNaN x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isDoubleNaN x) {- a _pure_function! -} + isInfinite x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isDoubleInfinite x) {- ditto -} + isDenormalized x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isDoubleDenormalized x) -- .. + isNegativeZero x = + (0::Int) /= unsafePerformPrimIO (_ccall_ isDoubleNegativeZero x) -- ... + isIEEE x = True instance Show Double where showsPrec x = showSigned showFloat x @@ -662,7 +700,7 @@ numericEnumFromThen n m = iterate (+(m-n)) n %********************************************************* \begin{code} -data (Integral a) => Ratio a = a :% a deriving (Eq) +data (Integral a) => Ratio a = !a :% !a deriving (Eq) type Rational = Ratio Integer \end{code} @@ -671,11 +709,19 @@ type Rational = Ratio Integer numerator, denominator :: (Integral a) => Ratio a -> a approxRational :: (RealFrac a) => a -> a -> Rational +\end{code} + +\tr{reduce} is a subsidiary function used only in this module . +It normalises a ratio by dividing both numerator and denominator by +their greatest common divisor. -reduce _ 0 = error "{Ratio.%}: zero denominator" +\begin{code} +reduce x 0 = error "{Ratio.%}: zero denominator" reduce x y = (x `quot` d) :% (y `quot` d) where d = gcd x y +\end{code} +\begin{code} x % y = reduce (x * signum y) (abs y) numerator (x:%y) = x @@ -702,8 +748,12 @@ approxRational x eps = simplest (x-eps) (x+eps) | x > 0 = simplest' n d n' d' | y < 0 = - simplest' (-n') d' (-n) d | otherwise = 0 :% 1 - where xr@(n:%d) = toRational x - (n':%d') = toRational y + where xr = toRational x + n = numerator xr + d = denominator xr + nd' = toRational y + n' = numerator nd' + d' = denominator nd' simplest' n d n' d' -- assumes 0 < n%d < n'%d' | r == 0 = q :% 1 @@ -711,7 +761,9 @@ approxRational x eps = simplest (x-eps) (x+eps) | otherwise = (q*n''+d'') :% n'' where (q,r) = quotRem n d (q',r') = quotRem n' d' - (n'':%d'') = simplest' d' r' d r + nd'' = simplest' d' r' d r + n'' = numerator nd'' + d'' = denominator nd'' \end{code} @@ -722,6 +774,7 @@ instance (Integral a) => Ord (Ratio a) where instance (Integral a) => Num (Ratio a) where (x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y') + (x:%y) - (x':%y') = reduce (x*y' - x'*y) (y*y') (x:%y) * (x':%y') = reduce (x * x') (y * y') negate (x:%y) = (-x) :% y abs (x:%y) = abs x :% y @@ -754,67 +807,9 @@ instance (Integral a) => Show (Ratio a) where (shows x . showString " % " . shows y) \end{code} -{- -[In response to a request by simonpj, Joe Fasel writes:] - -A quite reasonable request! This code was added to the Prelude just -before the 1.2 release, when Lennart, working with an early version -of hbi, noticed that (read . show) was not the identity for -floating-point numbers. (There was a one-bit error about half the time.) -The original version of the conversion function was in fact simply -a floating-point divide, as you suggest above. The new version is, -I grant you, somewhat denser. - -How's this? - -Joe --} - \begin{code} -{-# GENERATE_SPECS fromRational__ a{Double#,Double} #-} -fromRational__ :: (RealFloat a) => Rational -> a -fromRational__ x = x' - where x' = f e - --- If the exponent of the nearest floating-point number to x --- is e, then the significand is the integer nearest xb^(-e), --- where b is the floating-point radix. We start with a good --- guess for e, and if it is correct, the exponent of the --- floating-point number we construct will again be e. If --- not, one more iteration is needed. - - f e = if e' == e then y else f e' - where y = encodeFloat (round (x * (1 % b)^^e)) e - (_,e') = decodeFloat y - b = floatRadix x' - --- We obtain a trial exponent by doing a floating-point --- division of x's numerator by its denominator. The --- result of this division may not itself be the ultimate --- result, because of an accumulation of three rounding --- errors. - - (s,e) = decodeFloat (fromInteger (numerator x) `asTypeOf` x' - / fromInteger (denominator x)) -\end{code} - - -%********************************************************* -%* * -\subsection{Showing numbers} -%* * -%********************************************************* - -\begin{code} -showInteger n r - = case quotRem n 10 of { (n', d) -> - case (chr (ord_0 + fromIntegral d)) of { C# c# -> -- stricter than necessary - let - r' = C# c# : r - in - if n' == 0 then r' else showInteger n' r' - }} - +--Exported from std library Numeric, defined here to +--avoid mut. rec. between PrelNum and Numeric. showSigned :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS showSigned showPos p x = if x < 0 then showParen (p > 6) (showChar '-' . showPos (-x)) @@ -838,41 +833,175 @@ jtos' n cs chr (fromInteger (n + ord_0)) : cs else jtos' (n `quot` 10) (chr (fromInteger (n `rem` 10 + ord_0)) : cs) -\end{code} -The functions showFloat below uses rational arithmetic -to insure correct conversion between the floating-point radix and -decimal. It is often possible to use a higher-precision floating- -point type to obtain the same results. +showFloat x = showString (formatRealFloat FFGeneric Nothing x) + +-- These are the format types. This type is not exported. + +data FFFormat = FFExponent | FFFixed | FFGeneric --no need: deriving (Eq, Ord, Show) + +formatRealFloat :: (RealFloat a) => FFFormat -> Maybe Int -> a -> String +formatRealFloat fmt decs x = s + where + base = 10 + s = if isNaN x + then "NaN" + else + if isInfinite x then + if x < 0 then "-Infinity" else "Infinity" + else + if x < 0 || isNegativeZero x then + '-':doFmt fmt (floatToDigits (toInteger base) (-x)) + else + doFmt fmt (floatToDigits (toInteger base) x) + + doFmt fmt (is, e) = + let ds = map intToDigit is in + case fmt of + FFGeneric -> + doFmt (if e <0 || e > 7 then FFExponent else FFFixed) + (is,e) + FFExponent -> + case decs of + Nothing -> + let e' = if e==0 then 0 else e-1 in + (case ds of + [d] -> d : ".0e" + (d:ds) -> d : '.' : ds ++ "e") ++ show e' + Just dec -> + let dec' = max dec 1 in + case is of + [0] -> '0':'.':take dec' (repeat '0') ++ "e0" + _ -> + let + (ei,is') = roundTo base (dec'+1) is + d:ds = map intToDigit (if ei > 0 then init is' else is') + in + d:'.':ds ++ 'e':show (e-1+ei) + FFFixed -> + let + mk0 ls = case ls of { "" -> "0" ; _ -> ls} + in + case decs of + Nothing -> + let + f 0 s ds = mk0 (reverse s) ++ '.':mk0 ds + f n s "" = f (n-1) ('0':s) "" + f n s (d:ds) = f (n-1) (d:s) ds + in + f e "" ds + Just dec -> + let dec' = max dec 1 in + if e >= 0 then + let + (ei,is') = roundTo base (dec' + e) is + (ls,rs) = splitAt (e+ei) (map intToDigit is') + in + mk0 ls ++ (if null rs then "" else '.':rs) + else + let + (ei,is') = roundTo base dec' (replicate (-e) 0 ++ is) + d:ds = map intToDigit (if ei > 0 then is' else 0:is') + in + d : '.' : ds + + +roundTo :: Int -> Int -> [Int] -> (Int,[Int]) +roundTo base d is = + let + v = f d is + in + case v of + (0,is) -> v + (1,is) -> (1, 1:is) + where + b2 = base `div` 2 + + f n [] = (0, replicate n 0) + f 0 (i:_) = (if i>=b2 then 1 else 0, []) + f d (i:is) = + let + (c,ds) = f (d-1) is + i' = c + i + in + if i' == base then (1,0:ds) else (0,i':ds) + +-- +-- Based on "Printing Floating-Point Numbers Quickly and Accurately" +-- by R.G. Burger and R.K. Dybvig in PLDI 96. +-- This version uses a much slower logarithm estimator. It should be improved. + +-- This function returns a list of digits (Ints in [0..base-1]) and an +-- exponent. +--floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int) +floatToDigits _ 0 = ([0], 0) +floatToDigits base x = + let + (f0, e0) = decodeFloat x + (minExp0, _) = floatRange x + p = floatDigits x + b = floatRadix x + minExp = minExp0 - p -- the real minimum exponent + -- Haskell requires that f be adjusted so denormalized numbers + -- will have an impossibly low exponent. Adjust for this. + (f, e) = + let n = minExp - e0 in + if n > 0 then (f0 `div` (b^n), e0+n) else (f0, e0) + (r, s, mUp, mDn) = + if e >= 0 then + let be = b^ e in + if f == b^(p-1) then + (f*be*b*2, 2*b, be*b, b) + else + (f*be*2, 2, be, be) + else + if e > minExp && f == b^(p-1) then + (f*b*2, b^(-e+1)*2, b, 1) + else + (f*2, b^(-e)*2, 1, 1) + k = + let + k0 = + if b == 2 && base == 10 then + -- logBase 10 2 is slightly bigger than 3/10 so + -- the following will err on the low side. Ignoring + -- the fraction will make it err even more. + -- Haskell promises that p-1 <= logBase b f < p. + (p - 1 + e0) * 3 `div` 10 + else + ceiling ((log (fromInteger (f+1)) + + fromInt e * log (fromInteger b)) / + fromInt e * log (fromInteger b)) + + fixup n = + if n >= 0 then + if r + mUp <= expt base n * s then n else fixup (n+1) + else + if expt base (-n) * (r + mUp) <= s then n else fixup (n+1) + in + fixup k0 + + gen ds rn sN mUpN mDnN = + let + (dn, rn') = (rn * base) `divMod` sN + mUpN' = mUpN * base + mDnN' = mDnN * base + in + case (rn' < mDnN', rn' + mUpN' > sN) of + (True, False) -> dn : ds + (False, True) -> dn+1 : ds + (True, True) -> if rn' * 2 < sN then dn : ds else dn+1 : ds + (False, False) -> gen (dn:ds) rn' sN mUpN' mDnN' + + rds = + if k >= 0 then + gen [] r (s * expt base k) mUp mDn + else + let bk = expt base (-k) in + gen [] (r * bk) s (mUp * bk) (mDn * bk) + in + (map toInt (reverse rds), k) -\begin{code} -{-# GENERATE_SPECS showFloat a{Double#,Double} #-} -showFloat:: (RealFloat a) => a -> ShowS -showFloat x = - if x == 0 then showString ("0." ++ take (m-1) zeros) - else if e >= m-1 || e < 0 then showSci else showFix - where - showFix = showString whole . showChar '.' . showString frac - where (whole,frac) = splitAt (e+1) (show sig) - showSci = showChar d . showChar '.' . showString frac - . showChar 'e' . shows e - where (d:frac) = show sig - (m, sig, e) = if b == 10 then (w, s, n+w-1) - else (m', sig', e' ) - m' = ceiling - ((fromInt w * log (fromInteger b)) / log 10 :: Double) - + 1 - (sig', e') = if sig1 >= 10^m' then (round (t/10), e1+1) - else if sig1 < 10^(m'-1) then (round (t*10), e1-1) - else (sig1, e1 ) - sig1 = round t - t = s%1 * (b%1)^^n * 10^^(m'-e1-1) - e1 = floor (logBase 10 x) - (s, n) = decodeFloat x - b = floatRadix x - w = floatDigits x - -zeros = repeat '0' \end{code} @showRational@ converts a Rational to a string that looks like a @@ -923,6 +1052,125 @@ prR n r e0 = head s : "."++ drop0 (tail s) ++ "e" ++ show e0 \end{code} + +[In response to a request for documentation of how fromRational works, +Joe Fasel writes:] A quite reasonable request! This code was added to +the Prelude just before the 1.2 release, when Lennart, working with an +early version of hbi, noticed that (read . show) was not the identity +for floating-point numbers. (There was a one-bit error about half the +time.) The original version of the conversion function was in fact +simply a floating-point divide, as you suggest above. The new version +is, I grant you, somewhat denser. + +Unfortunately, Joe's code doesn't work! Here's an example: + +main = putStr (shows (1.82173691287639817263897126389712638972163e-300::Double) "\n") + +This program prints + 0.0000000000000000 +instead of + 1.8217369128763981e-300 + +Lennart's code follows, and it works... + +\begin{pseudocode} +{-# GENERATE_SPECS fromRational__ a{Double#,Double} #-} +fromRat :: (RealFloat a) => Rational -> a +fromRat x = x' + where x' = f e + +-- If the exponent of the nearest floating-point number to x +-- is e, then the significand is the integer nearest xb^(-e), +-- where b is the floating-point radix. We start with a good +-- guess for e, and if it is correct, the exponent of the +-- floating-point number we construct will again be e. If +-- not, one more iteration is needed. + + f e = if e' == e then y else f e' + where y = encodeFloat (round (x * (1 % b)^^e)) e + (_,e') = decodeFloat y + b = floatRadix x' + +-- We obtain a trial exponent by doing a floating-point +-- division of x's numerator by its denominator. The +-- result of this division may not itself be the ultimate +-- result, because of an accumulation of three rounding +-- errors. + + (s,e) = decodeFloat (fromInteger (numerator x) `asTypeOf` x' + / fromInteger (denominator x)) +\end{pseudocode} + +Now, here's Lennart's code. + +\begin{code} +--fromRat :: (RealFloat a) => Rational -> a +fromRat x = + if x == 0 then encodeFloat 0 0 -- Handle exceptional cases + else if x < 0 then - fromRat' (-x) -- first. + else fromRat' x + +-- Conversion process: +-- Scale the rational number by the RealFloat base until +-- it lies in the range of the mantissa (as used by decodeFloat/encodeFloat). +-- Then round the rational to an Integer and encode it with the exponent +-- that we got from the scaling. +-- To speed up the scaling process we compute the log2 of the number to get +-- a first guess of the exponent. + +fromRat' :: (RealFloat a) => Rational -> a +fromRat' x = r + where b = floatRadix r + p = floatDigits r + (minExp0, _) = floatRange r + minExp = minExp0 - p -- the real minimum exponent + xMin = toRational (expt b (p-1)) + xMax = toRational (expt b p) + p0 = (integerLogBase b (numerator x) - integerLogBase b (denominator x) - p) `max` minExp + f = if p0 < 0 then 1 % expt b (-p0) else expt b p0 % 1 + (x', p') = scaleRat (toRational b) minExp xMin xMax p0 (x / f) + r = encodeFloat (round x') p' + +-- Scale x until xMin <= x < xMax, or p (the exponent) <= minExp. +scaleRat :: Rational -> Int -> Rational -> Rational -> Int -> Rational -> (Rational, Int) +scaleRat b minExp xMin xMax p x = + if p <= minExp then + (x, p) + else if x >= xMax then + scaleRat b minExp xMin xMax (p+1) (x/b) + else if x < xMin then + scaleRat b minExp xMin xMax (p-1) (x*b) + else + (x, p) + +-- Exponentiation with a cache for the most common numbers. +minExpt = 0::Int +maxExpt = 1100::Int +expt :: Integer -> Int -> Integer +expt base n = + if base == 2 && n >= minExpt && n <= maxExpt then + expts!n + else + base^n +expts :: Array Int Integer +expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]] + +-- Compute the (floor of the) log of i in base b. +-- Simplest way would be just divide i by b until it's smaller then b, but that would +-- be very slow! We are just slightly more clever. +integerLogBase :: Integer -> Integer -> Int +integerLogBase b i = + if i < b then + 0 + else + -- Try squaring the base first to cut down the number of divisions. + let l = 2 * integerLogBase (b*b) i + doDiv :: Integer -> Int -> Int + doDiv i l = if i < b then l else doDiv (i `div` b) (l+1) + in doDiv (i `div` (b^l)) l +\end{code} + + %********************************************************* %* * \subsection{Numeric primops}