```{-# Language DeriveDataTypeable, DeriveGeneric #-}
{-|
Module      : Config.Number
Description : Scientific-notation numbers with explicit radix
Copyright   : (c) Eric Mertens, 2019
Maintainer  : emertens@gmail.com

This module provides a representation of numbers in scientific
notation.
-}
module Config.Number
( Number(..)
, numberToRational
, numberToInteger
, integerToNumber
, rationalToNumber
) where

import Data.Ratio (numerator, denominator)
import Data.Data (Data)
import GHC.Generics (Generic)

-- | Numbers are represented as base, coefficient, and exponent.
--
-- The most convenient way to get numbers into and out of this form
-- is to use one of: 'numberToRational', 'numberToInteger',
-- 'rationalToNumber', or 'integerToNumber'.
--
-- used to facilitate better pretty-printing. By using explicit
-- exponents extremely large numbers can be represented compactly.
-- Consider that it is easy to write `1e100000000` which would use
-- a significant amount of memory if realized as an 'Integer'. This
-- representation allows concerned programs to check bounds before
-- converting to a representation like 'Integer'.
data Number = MkNumber
, Number -> Rational
numberCoefficient :: !Rational
}
deriving (Number -> Number -> Bool
(Number -> Number -> Bool)
-> (Number -> Number -> Bool) -> Eq Number
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Number -> Number -> Bool
\$c/= :: Number -> Number -> Bool
== :: Number -> Number -> Bool
\$c== :: Number -> Number -> Bool
Eq, Eq Number
Eq Number
-> (Number -> Number -> Ordering)
-> (Number -> Number -> Bool)
-> (Number -> Number -> Bool)
-> (Number -> Number -> Bool)
-> (Number -> Number -> Bool)
-> (Number -> Number -> Number)
-> (Number -> Number -> Number)
-> Ord Number
Number -> Number -> Bool
Number -> Number -> Ordering
Number -> Number -> Number
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Number -> Number -> Number
\$cmin :: Number -> Number -> Number
max :: Number -> Number -> Number
\$cmax :: Number -> Number -> Number
>= :: Number -> Number -> Bool
\$c>= :: Number -> Number -> Bool
> :: Number -> Number -> Bool
\$c> :: Number -> Number -> Bool
<= :: Number -> Number -> Bool
\$c<= :: Number -> Number -> Bool
< :: Number -> Number -> Bool
\$c< :: Number -> Number -> Bool
compare :: Number -> Number -> Ordering
\$ccompare :: Number -> Number -> Ordering
\$cp1Ord :: Eq Number
forall a.
Read, Int -> Number -> ShowS
[Number] -> ShowS
Number -> String
(Int -> Number -> ShowS)
-> (Number -> String) -> ([Number] -> ShowS) -> Show Number
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Number] -> ShowS
\$cshowList :: [Number] -> ShowS
show :: Number -> String
\$cshow :: Number -> String
showsPrec :: Int -> Number -> ShowS
\$cshowsPrec :: Int -> Number -> ShowS
Show, Typeable Number
DataType
Constr
Typeable Number
-> (forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Number -> c Number)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Number)
-> (Number -> Constr)
-> (Number -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Number))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Number))
-> ((forall b. Data b => b -> b) -> Number -> Number)
-> (forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Number -> r)
-> (forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Number -> r)
-> (forall u. (forall d. Data d => d -> u) -> Number -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> Number -> u)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number)
-> Data Number
Number -> DataType
Number -> Constr
(forall b. Data b => b -> b) -> Number -> Number
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Number -> c Number
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Number
forall a.
Typeable a
-> (forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Number -> u
forall u. (forall d. Data d => d -> u) -> Number -> [u]
forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Number -> r
forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Number -> r
forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number
forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Number
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Number -> c Number
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Number)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Number)
\$cMkNumber :: Constr
\$tNumber :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> Number -> m Number
\$cgmapMo :: forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number
gmapMp :: (forall d. Data d => d -> m d) -> Number -> m Number
\$cgmapMp :: forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number
gmapM :: (forall d. Data d => d -> m d) -> Number -> m Number
\$cgmapM :: forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Number -> m Number
gmapQi :: Int -> (forall d. Data d => d -> u) -> Number -> u
\$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Number -> u
gmapQ :: (forall d. Data d => d -> u) -> Number -> [u]
\$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Number -> [u]
gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Number -> r
\$cgmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Number -> r
gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Number -> r
\$cgmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Number -> r
gmapT :: (forall b. Data b => b -> b) -> Number -> Number
\$cgmapT :: (forall b. Data b => b -> b) -> Number -> Number
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Number)
\$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Number)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c Number)
\$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Number)
dataTypeOf :: Number -> DataType
\$cdataTypeOf :: Number -> DataType
toConstr :: Number -> Constr
\$ctoConstr :: Number -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Number
\$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Number
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Number -> c Number
\$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Number -> c Number
\$cp1Data :: Typeable Number
Data, (forall x. Number -> Rep Number x)
-> (forall x. Rep Number x -> Number) -> Generic Number
forall x. Rep Number x -> Number
forall x. Number -> Rep Number x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
\$cto :: forall x. Rep Number x -> Number
\$cfrom :: forall x. Number -> Rep Number x
Generic)

-- | Radix used for a number. Some radix modes support an
-- exponent.
= Radix2           -- ^ binary, base 2
| Radix8           -- ^ octal, base 8
| Radix10 !Integer -- ^ decimal, base 10, exponent base 10
| Radix16 !Integer -- ^ hexdecimal, base 16, exponent base 2
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a.
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showsPrec :: Int -> Radix -> ShowS
\$cshowsPrec :: Int -> Radix -> ShowS
DataType
Constr
-> (forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Radix -> c Radix)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Radix)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Radix))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Radix))
-> ((forall b. Data b => b -> b) -> Radix -> Radix)
-> (forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r)
-> (forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r)
-> (forall u. (forall d. Data d => d -> u) -> Radix -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> Radix -> u)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix)
(forall b. Data b => b -> b) -> Radix -> Radix
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Radix -> c Radix
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Radix
forall a.
Typeable a
-> (forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
(forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Radix -> u
forall u. (forall d. Data d => d -> u) -> Radix -> [u]
forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r
forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r
forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix
forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Radix
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Radix -> c Radix
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Radix)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Radix)
gmapMo :: (forall d. Data d => d -> m d) -> Radix -> m Radix
\$cgmapMo :: forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix
gmapMp :: (forall d. Data d => d -> m d) -> Radix -> m Radix
\$cgmapMp :: forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix
gmapM :: (forall d. Data d => d -> m d) -> Radix -> m Radix
\$cgmapM :: forall (m :: * -> *).
(forall d. Data d => d -> m d) -> Radix -> m Radix
gmapQi :: Int -> (forall d. Data d => d -> u) -> Radix -> u
\$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Radix -> u
gmapQ :: (forall d. Data d => d -> u) -> Radix -> [u]
\$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Radix -> [u]
gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r
\$cgmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r
gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r
\$cgmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Radix -> r
gmapT :: (forall b. Data b => b -> b) -> Radix -> Radix
\$cgmapT :: (forall b. Data b => b -> b) -> Radix -> Radix
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Radix)
\$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Radix)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c Radix)
\$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Radix)
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Radix
\$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Radix
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Radix -> c Radix
\$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Radix -> c Radix
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
Generic)

-- | Returns the radix as an integer ignoring any exponent.
r =
r of
2
8
10
16

-- | Convert a number to a 'Rational'. Warning: This can use a
-- lot of memory in the case of very large exponent parts.
numberToRational :: Number -> Rational
numberToRational :: Number -> Rational
r Rational
c) =
r of
c
c
e -> Rational
c Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
10 Rational -> Integer -> Rational
forall a b. (Fractional a, Integral b) => a -> b -> a
^^ Integer
e
e -> Rational
c Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
*  Rational
2 Rational -> Integer -> Rational
forall a b. (Fractional a, Integral b) => a -> b -> a
^^ Integer
e

-- | Convert a number to a 'Integer'. Warning: This can use a
-- lot of memory in the case of very large exponent parts.
numberToInteger :: Number -> Maybe Integer
numberToInteger :: Number -> Maybe Integer
numberToInteger Number
n
| Rational -> Integer
forall a. Ratio a -> a
denominator Rational
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1 = Integer -> Maybe Integer
forall a. a -> Maybe a
Just (Integer -> Maybe Integer) -> Integer -> Maybe Integer
forall a b. (a -> b) -> a -> b
\$! Rational -> Integer
forall a. Ratio a -> a
numerator Rational
r
| Bool
otherwise          = Maybe Integer
forall a. Maybe a
Nothing
where
r :: Rational
r = Number -> Rational
numberToRational Number
n

-- | 'Integer' to a radix 10 'Number' with no exponent
integerToNumber :: Integer -> Number
integerToNumber :: Integer -> Number
integerToNumber = Rational -> Number
rationalToNumber (Rational -> Number) -> (Integer -> Rational) -> Integer -> Number
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Rational
forall a. Num a => Integer -> a
fromInteger

-- | 'Rational' to a radix 10 'Number' with no exponent
rationalToNumber :: Rational -> Number
rationalToNumber :: Rational -> Number
rationalToNumber = Radix -> Rational -> Number