{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude, MagicHash #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Numeric
-- Copyright   :  (c) The University of Glasgow 2002
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  portable
--
-- Odds and ends, mostly functions for reading and showing
-- 'RealFloat'-like kind of values.
--
-----------------------------------------------------------------------------

module Numeric (

        -- * Showing

        showSigned,

        showIntAtBase,
        showInt,
        showBin,
        showHex,
        showOct,

        showEFloat,
        showFFloat,
        showGFloat,
        showFFloatAlt,
        showGFloatAlt,
        showFloat,
        showHFloat,

        floatToDigits,

        -- * Reading

        -- | /NB:/ 'readInt' is the \'dual\' of 'showIntAtBase',
        -- and 'readDec' is the \`dual\' of 'showInt'.
        -- The inconsistent naming is a historical accident.

        readSigned,

        readInt,
        readBin,
        readDec,
        readOct,
        readHex,

        readFloat,

        lexDigits,

        -- * Miscellaneous

        fromRat,
        Floating(..)

        ) where

import GHC.Base
import GHC.Read
import GHC.Real
import GHC.Float
import GHC.Num
import GHC.Show
import Text.ParserCombinators.ReadP( ReadP, readP_to_S, pfail )
import qualified Text.Read.Lex as L

-- $setup
-- >>> import Prelude

-- -----------------------------------------------------------------------------
-- Reading

-- | Reads an /unsigned/ integral value in an arbitrary base.
readInt :: Num a
  => a                  -- ^ the base
  -> (Char -> Bool)     -- ^ a predicate distinguishing valid digits in this base
  -> (Char -> Int)      -- ^ a function converting a valid digit character to an 'Int'
  -> ReadS a
readInt :: forall a. Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
readInt a
base Char -> Bool
isDigit Char -> Int
valDigit = ReadP a -> ReadS a
forall a. ReadP a -> ReadS a
readP_to_S (a -> (Char -> Bool) -> (Char -> Int) -> ReadP a
forall a. Num a => a -> (Char -> Bool) -> (Char -> Int) -> ReadP a
L.readIntP a
base Char -> Bool
isDigit Char -> Int
valDigit)

-- | Read an unsigned number in binary notation.
--
-- >>> readBin "10011"
-- [(19,"")]
readBin :: (Eq a, Num a) => ReadS a
readBin :: forall a. (Eq a, Num a) => ReadS a
readBin = ReadP a -> ReadS a
forall a. ReadP a -> ReadS a
readP_to_S ReadP a
forall a. (Eq a, Num a) => ReadP a
L.readBinP

-- | Read an unsigned number in octal notation.
--
-- >>> readOct "0644"
-- [(420,"")]
readOct :: (Eq a, Num a) => ReadS a
readOct :: forall a. (Eq a, Num a) => ReadS a
readOct = ReadP a -> ReadS a
forall a. ReadP a -> ReadS a
readP_to_S ReadP a
forall a. (Eq a, Num a) => ReadP a
L.readOctP

-- | Read an unsigned number in decimal notation.
--
-- >>> readDec "0644"
-- [(644,"")]
readDec :: (Eq a, Num a) => ReadS a
readDec :: forall a. (Eq a, Num a) => ReadS a
readDec = ReadP a -> ReadS a
forall a. ReadP a -> ReadS a
readP_to_S ReadP a
forall a. (Eq a, Num a) => ReadP a
L.readDecP

-- | Read an unsigned number in hexadecimal notation.
-- Both upper or lower case letters are allowed.
--
-- >>> readHex "deadbeef"
-- [(3735928559,"")]
readHex :: (Eq a, Num a) => ReadS a
readHex :: forall a. (Eq a, Num a) => ReadS a
readHex = ReadP a -> ReadS a
forall a. ReadP a -> ReadS a
readP_to_S ReadP a
forall a. (Eq a, Num a) => ReadP a
L.readHexP

-- | Reads an /unsigned/ 'RealFrac' value,
-- expressed in decimal scientific notation.
readFloat :: RealFrac a => ReadS a
readFloat :: forall a. RealFrac a => ReadS a
readFloat = ReadP a -> ReadS a
forall a. ReadP a -> ReadS a
readP_to_S ReadP a
forall a. RealFrac a => ReadP a
readFloatP

readFloatP :: RealFrac a => ReadP a
readFloatP :: forall a. RealFrac a => ReadP a
readFloatP =
  do Lexeme
tok <- ReadP Lexeme
L.lex
     case Lexeme
tok of
       L.Number Number
n -> a -> ReadP a
forall a. a -> ReadP a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> ReadP a) -> a -> ReadP a
forall a b. (a -> b) -> a -> b
$ Rational -> a
forall a. Fractional a => Rational -> a
fromRational (Rational -> a) -> Rational -> a
forall a b. (a -> b) -> a -> b
$ Number -> Rational
L.numberToRational Number
n
       Lexeme
_          -> ReadP a
forall a. ReadP a
pfail

-- It's turgid to have readSigned work using list comprehensions,
-- but it's specified as a ReadS to ReadS transformer
-- With a bit of luck no one will use it.

-- | Reads a /signed/ 'Real' value, given a reader for an unsigned value.
readSigned :: (Real a) => ReadS a -> ReadS a
readSigned :: forall a. Real a => ReadS a -> ReadS a
readSigned ReadS a
readPos = Bool -> ReadS a -> ReadS a
forall a. Bool -> ReadS a -> ReadS a
readParen Bool
False ReadS a
read'
                     where read' :: ReadS a
read' String
r  = ReadS a
read'' String
r [(a, String)] -> [(a, String)] -> [(a, String)]
forall a. [a] -> [a] -> [a]
++
                                      (do
                                        (String
"-",String
s) <- ReadS String
lex String
r
                                        (a
x,String
t)   <- ReadS a
read'' String
s
                                        (a, String) -> [(a, String)]
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return (-a
x,String
t))
                           read'' :: ReadS a
read'' String
r = do
                               (String
str,String
s) <- ReadS String
lex String
r
                               (a
n,String
"")  <- ReadS a
readPos String
str
                               (a, String) -> [(a, String)]
forall a. a -> [a]
forall (m :: * -> *) a. Monad m => a -> m a
return (a
n,String
s)

-- -----------------------------------------------------------------------------
-- Showing

-- | Show /non-negative/ 'Integral' numbers in base 10.
showInt :: Integral a => a -> ShowS
showInt :: forall a. Integral a => a -> ShowS
showInt a
n0 String
cs0
    | a
n0 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0    = ShowS
forall a. String -> a
errorWithoutStackTrace String
"Numeric.showInt: can't show negative numbers"
    | Bool
otherwise = a -> ShowS
forall a. Integral a => a -> ShowS
go a
n0 String
cs0
    where
    go :: t -> ShowS
go t
n String
cs
        | t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< t
10    = case Int -> Char
unsafeChr (Char -> Int
ord Char
'0' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ t -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral t
n) of
            c :: Char
c@(C# Char#
_) -> Char
cChar -> ShowS
forall a. a -> [a] -> [a]
:String
cs
        | Bool
otherwise = case Int -> Char
unsafeChr (Char -> Int
ord Char
'0' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ t -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral t
r) of
            c :: Char
c@(C# Char#
_) -> t -> ShowS
go t
q (Char
cChar -> ShowS
forall a. a -> [a] -> [a]
:String
cs)
        where
        (t
q,t
r) = t
n t -> t -> (t, t)
forall a. Integral a => a -> a -> (a, a)
`quotRem` t
10

-- Controlling the format and precision of floats. The code that
-- implements the formatting itself is in @PrelNum@ to avoid
-- mutual module deps.

{-# SPECIALIZE showEFloat ::
        Maybe Int -> Float  -> ShowS,
        Maybe Int -> Double -> ShowS #-}
{-# SPECIALIZE showFFloat ::
        Maybe Int -> Float  -> ShowS,
        Maybe Int -> Double -> ShowS #-}
{-# SPECIALIZE showGFloat ::
        Maybe Int -> Float  -> ShowS,
        Maybe Int -> Double -> ShowS #-}

-- | Show a signed 'RealFloat' value
-- using scientific (exponential) notation (e.g. @2.45e2@, @1.5e-3@).
--
-- In the call @'showEFloat' digs val@, if @digs@ is 'Nothing',
-- the value is shown to full precision; if @digs@ is @'Just' d@,
-- then at most @d@ digits after the decimal point are shown.
showEFloat    :: (RealFloat a) => Maybe Int -> a -> ShowS

-- | Show a signed 'RealFloat' value
-- using standard decimal notation (e.g. @245000@, @0.0015@).
--
-- In the call @'showFFloat' digs val@, if @digs@ is 'Nothing',
-- the value is shown to full precision; if @digs@ is @'Just' d@,
-- then at most @d@ digits after the decimal point are shown.
showFFloat    :: (RealFloat a) => Maybe Int -> a -> ShowS

-- | Show a signed 'RealFloat' value
-- using standard decimal notation for arguments whose absolute value lies
-- between @0.1@ and @9,999,999@, and scientific notation otherwise.
--
-- In the call @'showGFloat' digs val@, if @digs@ is 'Nothing',
-- the value is shown to full precision; if @digs@ is @'Just' d@,
-- then at most @d@ digits after the decimal point are shown.
showGFloat    :: (RealFloat a) => Maybe Int -> a -> ShowS

showEFloat :: forall a. RealFloat a => Maybe Int -> a -> ShowS
showEFloat Maybe Int
d a
x =  String -> ShowS
showString (FFFormat -> Maybe Int -> a -> String
forall a. RealFloat a => FFFormat -> Maybe Int -> a -> String
formatRealFloat FFFormat
FFExponent Maybe Int
d a
x)
showFFloat :: forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
d a
x =  String -> ShowS
showString (FFFormat -> Maybe Int -> a -> String
forall a. RealFloat a => FFFormat -> Maybe Int -> a -> String
formatRealFloat FFFormat
FFFixed Maybe Int
d a
x)
showGFloat :: forall a. RealFloat a => Maybe Int -> a -> ShowS
showGFloat Maybe Int
d a
x =  String -> ShowS
showString (FFFormat -> Maybe Int -> a -> String
forall a. RealFloat a => FFFormat -> Maybe Int -> a -> String
formatRealFloat FFFormat
FFGeneric Maybe Int
d a
x)

-- | Show a signed 'RealFloat' value
-- using standard decimal notation (e.g. @245000@, @0.0015@).
--
-- This behaves as 'showFFloat', except that a decimal point
-- is always guaranteed, even if not needed.
--
-- @since 4.7.0.0
showFFloatAlt    :: (RealFloat a) => Maybe Int -> a -> ShowS

-- | Show a signed 'RealFloat' value
-- using standard decimal notation for arguments whose absolute value lies
-- between @0.1@ and @9,999,999@, and scientific notation otherwise.
--
-- This behaves as 'showFFloat', except that a decimal point
-- is always guaranteed, even if not needed.
--
-- @since 4.7.0.0
showGFloatAlt    :: (RealFloat a) => Maybe Int -> a -> ShowS

showFFloatAlt :: forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloatAlt Maybe Int
d a
x =  String -> ShowS
showString (FFFormat -> Maybe Int -> Bool -> a -> String
forall a.
RealFloat a =>
FFFormat -> Maybe Int -> Bool -> a -> String
formatRealFloatAlt FFFormat
FFFixed Maybe Int
d Bool
True a
x)
showGFloatAlt :: forall a. RealFloat a => Maybe Int -> a -> ShowS
showGFloatAlt Maybe Int
d a
x =  String -> ShowS
showString (FFFormat -> Maybe Int -> Bool -> a -> String
forall a.
RealFloat a =>
FFFormat -> Maybe Int -> Bool -> a -> String
formatRealFloatAlt FFFormat
FFGeneric Maybe Int
d Bool
True a
x)

{- | Show a floating-point value in the hexadecimal format,
similar to the @%a@ specifier in C's printf.

  >>> showHFloat (212.21 :: Double) ""
  "0x1.a86b851eb851fp7"
  >>> showHFloat (-12.76 :: Float) ""
  "-0x1.9851ecp3"
  >>> showHFloat (-0 :: Double) ""
  "-0x0p+0"
-}
showHFloat :: RealFloat a => a -> ShowS
showHFloat :: forall a. RealFloat a => a -> ShowS
showHFloat = String -> ShowS
showString (String -> ShowS) -> (a -> String) -> a -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall {a}. RealFloat a => a -> String
fmt
  where
  fmt :: a -> String
fmt a
x
    | a -> Bool
forall a. RealFloat a => a -> Bool
isNaN a
x                   = String
"NaN"
    | a -> Bool
forall a. RealFloat a => a -> Bool
isInfinite a
x              = (if a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 then String
"-" else String
"") String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"Infinity"
    | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 Bool -> Bool -> Bool
|| a -> Bool
forall a. RealFloat a => a -> Bool
isNegativeZero a
x = Char
'-' Char -> ShowS
forall a. a -> [a] -> [a]
: a -> String
forall {a}. RealFloat a => a -> String
cvt (-a
x)
    | Bool
otherwise                 = a -> String
forall {a}. RealFloat a => a -> String
cvt a
x

  cvt :: a -> String
cvt a
x
    | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = String
"0x0p+0"
    | Bool
otherwise =
      case Integer -> a -> ([Int], Int)
forall a. RealFloat a => Integer -> a -> ([Int], Int)
floatToDigits Integer
2 a
x of
        r :: ([Int], Int)
r@([], Int
_) -> ShowS
forall a. HasCallStack => String -> a
error ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String
"Impossible happened: showHFloat: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ([Int], Int) -> String
forall a. Show a => a -> String
show ([Int], Int)
r
        (Int
d:[Int]
ds, Int
e) -> String
"0x" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
d String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Int] -> String
forall {a}. Integral a => [a] -> String
frac [Int]
ds String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"p" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Int
eInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)

  -- Given binary digits, convert them to hex in blocks of 4
  -- Special case: If all 0's, just drop it.
  frac :: [a] -> String
frac [a]
digits
    | [a] -> Bool
forall {a}. (Eq a, Num a) => [a] -> Bool
allZ [a]
digits = String
""
    | Bool
otherwise   = String
"." String -> ShowS
forall a. [a] -> [a] -> [a]
++ [a] -> String
forall {a}. Integral a => [a] -> String
hex [a]
digits
    where
    hex :: [a] -> String
hex [a]
ds =
      case [a]
ds of
        []                -> String
""
        [a
a]               -> a -> a -> a -> a -> ShowS
forall {a}. Integral a => a -> a -> a -> a -> ShowS
hexDigit a
a a
0 a
0 a
0 String
""
        [a
a,a
b]             -> a -> a -> a -> a -> ShowS
forall {a}. Integral a => a -> a -> a -> a -> ShowS
hexDigit a
a a
b a
0 a
0 String
""
        [a
a,a
b,a
c]           -> a -> a -> a -> a -> ShowS
forall {a}. Integral a => a -> a -> a -> a -> ShowS
hexDigit a
a a
b a
c a
0 String
""
        a
a : a
b : a
c : a
d : [a]
r -> a -> a -> a -> a -> ShowS
forall {a}. Integral a => a -> a -> a -> a -> ShowS
hexDigit a
a a
b a
c a
d ([a] -> String
hex [a]
r)

  hexDigit :: a -> a -> a -> a -> ShowS
hexDigit a
a a
b a
c a
d = a -> ShowS
forall a. Integral a => a -> ShowS
showHex (a
8a -> a -> a
forall a. Num a => a -> a -> a
*a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
4a -> a -> a
forall a. Num a => a -> a -> a
*a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a
2a -> a -> a
forall a. Num a => a -> a -> a
*a
c a -> a -> a
forall a. Num a => a -> a -> a
+ a
d)

  allZ :: [a] -> Bool
allZ [a]
xs = case [a]
xs of
              a
x : [a]
more -> a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 Bool -> Bool -> Bool
&& [a] -> Bool
allZ [a]
more
              []       -> Bool
True

-- ---------------------------------------------------------------------------
-- Integer printing functions

-- | Shows a /non-negative/ 'Integral' number using the base specified by the
-- first argument, and the character representation specified by the second.
showIntAtBase :: Integral a => a -> (Int -> Char) -> a -> ShowS
showIntAtBase :: forall a. Integral a => a -> (Int -> Char) -> a -> ShowS
showIntAtBase a
base Int -> Char
toChr a
n0 String
r0
  | a
base a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1 = ShowS
forall a. String -> a
errorWithoutStackTrace (String
"Numeric.showIntAtBase: applied to unsupported base " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
base))
  | a
n0 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<  a
0   = ShowS
forall a. String -> a
errorWithoutStackTrace (String
"Numeric.showIntAtBase: applied to negative number " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n0))
  | Bool
otherwise = (a, a) -> ShowS
showIt (a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
quotRem a
n0 a
base) String
r0
   where
    showIt :: (a, a) -> ShowS
showIt (a
n,a
d) String
r = Char -> ShowS
forall a b. a -> b -> b
seq Char
c ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ -- stricter than necessary
      case a
n of
        a
0 -> String
r'
        a
_ -> (a, a) -> ShowS
showIt (a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
quotRem a
n a
base) String
r'
     where
      c :: Char
c  = Int -> Char
toChr (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
d)
      r' :: String
r' = Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: String
r

-- | Show /non-negative/ 'Integral' numbers in base 16.
showHex :: Integral a => a -> ShowS
showHex :: forall a. Integral a => a -> ShowS
showHex = a -> (Int -> Char) -> a -> ShowS
forall a. Integral a => a -> (Int -> Char) -> a -> ShowS
showIntAtBase a
16 Int -> Char
intToDigit

-- | Show /non-negative/ 'Integral' numbers in base 8.
showOct :: Integral a => a -> ShowS
showOct :: forall a. Integral a => a -> ShowS
showOct = a -> (Int -> Char) -> a -> ShowS
forall a. Integral a => a -> (Int -> Char) -> a -> ShowS
showIntAtBase a
8  Int -> Char
intToDigit

-- | Show /non-negative/ 'Integral' numbers in base 2.
showBin :: Integral a => a -> ShowS
showBin :: forall a. Integral a => a -> ShowS
showBin = a -> (Int -> Char) -> a -> ShowS
forall a. Integral a => a -> (Int -> Char) -> a -> ShowS
showIntAtBase a
2  Int -> Char
intToDigit