summaryrefslogtreecommitdiff
path: root/libraries/ghc-bignum/src/GHC/Num/Integer.hs
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2019-09-19 16:26:52 +0200
committerBen Gamari <ben@smart-cactus.org>2020-06-17 16:22:03 -0400
commit9f96bc127d6231b5e76bbab442244eb303b08867 (patch)
tree3b40983164af5d78e7efe8cdb7e580ba36819f79 /libraries/ghc-bignum/src/GHC/Num/Integer.hs
parent57db91d8ee501c7cf176c4bb1e2101d3092fd0f6 (diff)
downloadhaskell-9f96bc127d6231b5e76bbab442244eb303b08867.tar.gz
ghc-bignum library
ghc-bignum is a newer package that aims to replace the legacy integer-simple and integer-gmp packages. * it supports several backends. In particular GMP is still supported and most of the code from integer-gmp has been merged in the "gmp" backend. * the pure Haskell "native" backend is new and is much faster than the previous pure Haskell implementation provided by integer-simple * new backends are easier to write because they only have to provide a few well defined functions. All the other code is common to all backends. In particular they all share the efficient small/big number distinction previously used only in integer-gmp. * backends can all be tested against the "native" backend with a simple Cabal flag. Backends are only allowed to differ in performance, their results should be the same. * Add `integer-gmp` compat package: provide some pattern synonyms and function aliases for those in `ghc-bignum`. It is intended to avoid breaking packages that depend on `integer-gmp` internals. Update submodules: text, bytestring Metric Decrease: Conversions ManyAlternatives ManyConstructors Naperian T10359 T10547 T10678 T12150 T12227 T12234 T12425 T13035 T13719 T14936 T1969 T4801 T4830 T5237 T5549 T5837 T8766 T9020 parsing001 space_leak_001 T16190 haddock.base On ARM and i386, T17499 regresses (+6% > 5%). On x86_64 unregistered, T13701 sometimes regresses (+2.2% > 2%). Metric Increase: T17499 T13701
Diffstat (limited to 'libraries/ghc-bignum/src/GHC/Num/Integer.hs')
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/Integer.hs1169
1 files changed, 1169 insertions, 0 deletions
diff --git a/libraries/ghc-bignum/src/GHC/Num/Integer.hs b/libraries/ghc-bignum/src/GHC/Num/Integer.hs
new file mode 100644
index 0000000000..b4f6ee0c54
--- /dev/null
+++ b/libraries/ghc-bignum/src/GHC/Num/Integer.hs
@@ -0,0 +1,1169 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE NegativeLiterals #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE BlockArguments #-}
+
+-- |
+-- Module : GHC.Num.Integer
+-- Copyright : (c) Sylvain Henry 2019,
+-- (c) Herbert Valerio Riedel 2014
+-- License : BSD3
+--
+-- Maintainer : sylvain@haskus.fr
+-- Stability : provisional
+-- Portability : non-portable (GHC Extensions)
+--
+-- The 'Integer' type.
+
+module GHC.Num.Integer where
+
+#include "MachDeps.h"
+#include "WordSize.h"
+
+import GHC.Prim
+import GHC.Types
+import GHC.Classes
+import GHC.Magic
+import GHC.Num.Primitives
+import GHC.Num.BigNat
+import GHC.Num.Natural
+
+#if WORD_SIZE_IN_BITS < 64
+import GHC.IntWord64
+#endif
+
+default ()
+
+-- | Arbitrary precision integers. In contrast with fixed-size integral types
+-- such as 'Int', the 'Integer' type represents the entire infinite range of
+-- integers.
+--
+-- Integers are stored in a kind of sign-magnitude form, hence do not expect
+-- two's complement form when using bit operations.
+--
+-- If the value is small (fit into an 'Int'), 'IS' constructor is used.
+-- Otherwise 'IP' and 'IN' constructors are used to store a 'BigNat'
+-- representing respectively the positive or the negative value magnitude.
+--
+-- Invariant: 'IP' and 'IN' are used iff value doesn't fit in 'IS'
+data Integer
+ = IS !Int# -- ^ iff value in @[minBound::'Int', maxBound::'Int']@ range
+ | IP !BigNat -- ^ iff value in @]maxBound::'Int', +inf[@ range
+ | IN !BigNat -- ^ iff value in @]-inf, minBound::'Int'[@ range
+
+
+-- | Check Integer invariants
+integerCheck# :: Integer -> Bool#
+integerCheck# (IS _) = 1#
+integerCheck# (IP bn) = bigNatCheck# bn &&# (bn `bigNatGtWord#` INT_MAXBOUND##)
+integerCheck# (IN bn) = bigNatCheck# bn &&# (bn `bigNatGtWord#` ABS_INT_MINBOUND##)
+
+-- | Check Integer invariants
+integerCheck :: Integer -> Bool
+integerCheck i = isTrue# (integerCheck# i)
+
+-- | Integer Zero
+integerZero :: Integer
+integerZero = IS 0#
+
+-- | Integer One
+integerOne :: Integer
+integerOne = IS 1#
+
+---------------------------------------------------------------------
+-- Conversions
+---------------------------------------------------------------------
+
+-- | Create a positive Integer from a BigNat
+integerFromBigNat :: BigNat -> Integer
+integerFromBigNat !bn
+ | bigNatIsZero bn
+ = integerZero
+
+ | isTrue# (bn `bigNatLeWord#` INT_MAXBOUND##)
+ = IS (word2Int# (bigNatIndex# bn 0#))
+
+ | True
+ = IP bn
+
+-- | Create a negative Integer from a BigNat
+integerFromBigNatNeg :: BigNat -> Integer
+integerFromBigNatNeg !bn
+ | bigNatIsZero bn
+ = integerZero
+
+ | 1# <- bigNatSize# bn
+ , i <- negateInt# (word2Int# (bigNatIndex# bn 0#))
+ , isTrue# (i <=# 0#)
+ = IS i
+
+ | True
+ = IN bn
+
+-- | Create an Integer from a sign-bit and a BigNat
+integerFromBigNatSign :: Int# -> BigNat -> Integer
+integerFromBigNatSign !sign !bn
+ | 0# <- sign
+ = integerFromBigNat bn
+
+ | True
+ = integerFromBigNatNeg bn
+
+-- | Convert an Integer into a BigNat.
+--
+-- Return 0 for negative Integers.
+integerToBigNatClamp :: Integer -> BigNat
+integerToBigNatClamp (IP x) = x
+integerToBigNatClamp (IS x)
+ | isTrue# (x >=# 0#) = bigNatFromWord# (int2Word# x)
+integerToBigNatClamp _ = bigNatZero void#
+
+-- | Create an Integer from an Int#
+integerFromInt# :: Int# -> Integer
+integerFromInt# i = IS i
+
+-- | Create an Integer from an Int
+integerFromInt :: Int -> Integer
+integerFromInt (I# i) = IS i
+
+-- | Truncates 'Integer' to least-significant 'Int#'
+integerToInt# :: Integer -> Int#
+{-# NOINLINE integerToInt# #-}
+integerToInt# (IS i) = i
+integerToInt# (IP b) = word2Int# (bigNatToWord# b)
+integerToInt# (IN b) = negateInt# (word2Int# (bigNatToWord# b))
+
+-- | Truncates 'Integer' to least-significant 'Int#'
+integerToInt :: Integer -> Int
+integerToInt i = I# (integerToInt# i)
+
+-- | Convert a Word# into an Integer
+integerFromWord# :: Word# -> Integer
+{-# NOINLINE integerFromWord# #-}
+integerFromWord# w
+ | i <- word2Int# w
+ , isTrue# (i >=# 0#)
+ = IS i
+
+ | True
+ = IP (bigNatFromWord# w)
+
+-- | Convert a Word into an Integer
+integerFromWord :: Word -> Integer
+integerFromWord (W# w) = integerFromWord# w
+
+-- | Create a negative Integer with the given Word magnitude
+integerFromWordNeg# :: Word# -> Integer
+integerFromWordNeg# w
+ | isTrue# (w `leWord#` ABS_INT_MINBOUND##)
+ = IS (negateInt# (word2Int# w))
+
+ | True
+ = IN (bigNatFromWord# w)
+
+-- | Create an Integer from a sign and a Word magnitude
+integerFromWordSign# :: Int# -> Word# -> Integer
+integerFromWordSign# 0# w = integerFromWord# w
+integerFromWordSign# _ w = integerFromWordNeg# w
+
+-- | Truncate an Integer into a Word
+integerToWord# :: Integer -> Word#
+{-# NOINLINE integerToWord# #-}
+integerToWord# (IS i) = int2Word# i
+integerToWord# (IP bn) = bigNatToWord# bn
+integerToWord# (IN bn) = int2Word# (negateInt# (word2Int# (bigNatToWord# bn)))
+
+-- | Truncate an Integer into a Word
+integerToWord :: Integer -> Word
+integerToWord !i = W# (integerToWord# i)
+
+-- | Convert a Natural into an Integer
+integerFromNatural :: Natural -> Integer
+{-# NOINLINE integerFromNatural #-}
+integerFromNatural (NS x) = integerFromWord# x
+integerFromNatural (NB x) = integerFromBigNat x
+
+-- | Convert a list of Word into an Integer
+integerFromWordList :: Bool -> [Word] -> Integer
+integerFromWordList True ws = integerFromBigNatNeg (bigNatFromWordList ws)
+integerFromWordList False ws = integerFromBigNat (bigNatFromWordList ws)
+
+-- | Convert a Integer into a Natural
+--
+-- Return 0 for negative Integers.
+integerToNaturalClamp :: Integer -> Natural
+{-# NOINLINE integerToNaturalClamp #-}
+integerToNaturalClamp (IS x)
+ | isTrue# (x <# 0#) = naturalZero
+ | True = naturalFromWord# (int2Word# x)
+integerToNaturalClamp (IP x) = naturalFromBigNat x
+integerToNaturalClamp (IN _) = naturalZero
+
+-- | Convert a Integer into a Natural
+--
+-- Return absolute value
+integerToNatural :: Integer -> Natural
+{-# NOINLINE integerToNatural #-}
+integerToNatural (IS x) = naturalFromWord# (wordFromAbsInt# x)
+integerToNatural (IP x) = naturalFromBigNat x
+integerToNatural (IN x) = naturalFromBigNat x
+
+---------------------------------------------------------------------
+-- Predicates
+---------------------------------------------------------------------
+
+-- | Negative predicate
+integerIsNegative# :: Integer -> Bool#
+integerIsNegative# (IS i#) = i# <# 0#
+integerIsNegative# (IP _) = 0#
+integerIsNegative# (IN _) = 1#
+
+-- | Negative predicate
+integerIsNegative :: Integer -> Bool
+integerIsNegative !i = isTrue# (integerIsNegative# i)
+
+-- | Zero predicate
+integerIsZero :: Integer -> Bool
+integerIsZero (IS 0#) = True
+integerIsZero _ = False
+
+-- | Not-equal predicate.
+integerNe :: Integer -> Integer -> Bool
+integerNe !x !y = isTrue# (integerNe# x y)
+
+-- | Equal predicate.
+integerEq :: Integer -> Integer -> Bool
+integerEq !x !y = isTrue# (integerEq# x y)
+
+-- | Lower-or-equal predicate.
+integerLe :: Integer -> Integer -> Bool
+integerLe !x !y = isTrue# (integerLe# x y)
+
+-- | Lower predicate.
+integerLt :: Integer -> Integer -> Bool
+integerLt !x !y = isTrue# (integerLt# x y)
+
+-- | Greater predicate.
+integerGt :: Integer -> Integer -> Bool
+integerGt !x !y = isTrue# (integerGt# x y)
+
+-- | Greater-or-equal predicate.
+integerGe :: Integer -> Integer -> Bool
+integerGe !x !y = isTrue# (integerGe# x y)
+
+-- | Equal predicate.
+integerEq# :: Integer -> Integer -> Bool#
+{-# NOINLINE integerEq# #-}
+integerEq# (IS x) (IS y) = x ==# y
+integerEq# (IN x) (IN y) = bigNatEq# x y
+integerEq# (IP x) (IP y) = bigNatEq# x y
+integerEq# _ _ = 0#
+
+-- | Not-equal predicate.
+integerNe# :: Integer -> Integer -> Bool#
+{-# NOINLINE integerNe# #-}
+integerNe# (IS x) (IS y) = x /=# y
+integerNe# (IN x) (IN y) = bigNatNe# x y
+integerNe# (IP x) (IP y) = bigNatNe# x y
+integerNe# _ _ = 1#
+
+-- | Greater predicate.
+integerGt# :: Integer -> Integer -> Bool#
+{-# NOINLINE integerGt# #-}
+integerGt# (IS x) (IS y) = x ># y
+integerGt# x y | GT <- integerCompare x y = 1#
+integerGt# _ _ = 0#
+
+-- | Lower-or-equal predicate.
+integerLe# :: Integer -> Integer -> Bool#
+{-# NOINLINE integerLe# #-}
+integerLe# (IS x) (IS y) = x <=# y
+integerLe# x y | GT <- integerCompare x y = 0#
+integerLe# _ _ = 1#
+
+-- | Lower predicate.
+integerLt# :: Integer -> Integer -> Bool#
+{-# NOINLINE integerLt# #-}
+integerLt# (IS x) (IS y) = x <# y
+integerLt# x y | LT <- integerCompare x y = 1#
+integerLt# _ _ = 0#
+
+-- | Greater-or-equal predicate.
+integerGe# :: Integer -> Integer -> Bool#
+{-# NOINLINE integerGe# #-}
+integerGe# (IS x) (IS y) = x >=# y
+integerGe# x y | LT <- integerCompare x y = 0#
+integerGe# _ _ = 1#
+
+instance Eq Integer where
+ (==) = integerEq
+ (/=) = integerNe
+
+-- | Compare two Integer
+integerCompare :: Integer -> Integer -> Ordering
+{-# NOINLINE integerCompare #-}
+integerCompare (IS x) (IS y) = compareInt# x y
+integerCompare (IP x) (IP y) = bigNatCompare x y
+integerCompare (IN x) (IN y) = bigNatCompare y x
+integerCompare (IS _) (IP _) = LT
+integerCompare (IS _) (IN _) = GT
+integerCompare (IP _) (IS _) = GT
+integerCompare (IN _) (IS _) = LT
+integerCompare (IP _) (IN _) = GT
+integerCompare (IN _) (IP _) = LT
+
+instance Ord Integer where
+ compare = integerCompare
+
+---------------------------------------------------------------------
+-- Operations
+---------------------------------------------------------------------
+
+-- | Subtract one 'Integer' from another.
+integerSub :: Integer -> Integer -> Integer
+{-# NOINLINE integerSub #-}
+integerSub !x (IS 0#) = x
+integerSub (IS x#) (IS y#)
+ = case subIntC# x# y# of
+ (# z#, 0# #) -> IS z#
+ (# 0#, _ #) -> IN (bigNatFromWord2# 1## 0##)
+ (# z#, _ #)
+ | isTrue# (z# ># 0#)
+ -> IN (bigNatFromWord# ( (int2Word# (negateInt# z#))))
+ | True
+ -> IP (bigNatFromWord# ( (int2Word# z#)))
+integerSub (IS x#) (IP y)
+ | isTrue# (x# >=# 0#)
+ = integerFromBigNatNeg (bigNatSubWordUnsafe# y (int2Word# x#))
+ | True
+ = IN (bigNatAddWord# y (int2Word# (negateInt# x#)))
+integerSub (IS x#) (IN y)
+ | isTrue# (x# >=# 0#)
+ = IP (bigNatAddWord# y (int2Word# x#))
+ | True
+ = integerFromBigNat (bigNatSubWordUnsafe# y (int2Word# (negateInt# x#)))
+integerSub (IP x) (IP y)
+ = case bigNatCompare x y of
+ LT -> integerFromBigNatNeg (bigNatSubUnsafe y x)
+ EQ -> IS 0#
+ GT -> integerFromBigNat (bigNatSubUnsafe x y)
+integerSub (IP x) (IN y) = IP (bigNatAdd x y)
+integerSub (IN x) (IP y) = IN (bigNatAdd x y)
+integerSub (IN x) (IN y)
+ = case bigNatCompare x y of
+ LT -> integerFromBigNat (bigNatSubUnsafe y x)
+ EQ -> IS 0#
+ GT -> integerFromBigNatNeg (bigNatSubUnsafe x y)
+integerSub (IP x) (IS y#)
+ | isTrue# (y# >=# 0#)
+ = integerFromBigNat (bigNatSubWordUnsafe# x (int2Word# y#))
+ | True
+ = IP (bigNatAddWord# x (int2Word# (negateInt# y#)))
+integerSub (IN x) (IS y#)
+ | isTrue# (y# >=# 0#)
+ = IN (bigNatAddWord# x (int2Word# y#))
+ | True
+ = integerFromBigNatNeg (bigNatSubWordUnsafe# x (int2Word# (negateInt# y#)))
+
+-- | Add two 'Integer's
+integerAdd :: Integer -> Integer -> Integer
+{-# NOINLINE integerAdd #-}
+integerAdd !x (IS 0#) = x
+integerAdd (IS 0#) y = y
+integerAdd (IS x#) (IS y#)
+ = case addIntC# x# y# of
+ (# z#, 0# #) -> IS z#
+ (# 0#, _ #) -> IN (bigNatFromWord2# 1## 0##) -- 2*minBound::Int
+ (# z#, _ #)
+ | isTrue# (z# ># 0#) -> IN (bigNatFromWord# ( (int2Word# (negateInt# z#))))
+ | True -> IP (bigNatFromWord# ( (int2Word# z#)))
+integerAdd y@(IS _) x = integerAdd x y
+integerAdd (IP x) (IP y) = IP (bigNatAdd x y)
+integerAdd (IN x) (IN y) = IN (bigNatAdd x y)
+integerAdd (IP x) (IS y#) -- edge-case: @(maxBound+1) + minBound == 0@
+ | isTrue# (y# >=# 0#) = IP (bigNatAddWord# x (int2Word# y#))
+ | True = integerFromBigNat (bigNatSubWordUnsafe# x (int2Word#
+ (negateInt# y#)))
+integerAdd (IN x) (IS y#) -- edge-case: @(minBound-1) + maxBound == -2@
+ | isTrue# (y# >=# 0#) = integerFromBigNatNeg (bigNatSubWordUnsafe# x (int2Word# y#))
+ | True = IN (bigNatAddWord# x (int2Word# (negateInt# y#)))
+integerAdd y@(IN _) x@(IP _) = integerAdd x y
+integerAdd (IP x) (IN y)
+ = case bigNatCompare x y of
+ LT -> integerFromBigNatNeg (bigNatSubUnsafe y x)
+ EQ -> IS 0#
+ GT -> integerFromBigNat (bigNatSubUnsafe x y)
+
+-- | Multiply two 'Integer's
+integerMul :: Integer -> Integer -> Integer
+{-# NOINLINE integerMul #-}
+integerMul !_ (IS 0#) = IS 0#
+integerMul (IS 0#) _ = IS 0#
+integerMul x (IS 1#) = x
+integerMul (IS 1#) y = y
+integerMul x (IS -1#) = integerNegate x
+integerMul (IS -1#) y = integerNegate y
+#if __GLASGOW_HASKELL__ < 809
+integerMul (IS x) (IS y) = case mulIntMayOflo# x y of
+ 0# -> IS (x *# y)
+ _ -> case (# isTrue# (x >=# 0#), isTrue# (y >=# 0#) #) of
+ (# False, False #) -> case timesWord2# (int2Word# (negateInt# x))
+ (int2Word# (negateInt# y)) of
+ (# 0##,l #) -> integerFromWord# l
+ (# h ,l #) -> IP (bigNatFromWord2# h l)
+
+ (# True, False #) -> case timesWord2# (int2Word# x)
+ (int2Word# (negateInt# y)) of
+ (# 0##,l #) -> integerFromWordNeg# l
+ (# h ,l #) -> IN (bigNatFromWord2# h l)
+
+ (# False, True #) -> case timesWord2# (int2Word# (negateInt# x))
+ (int2Word# y) of
+ (# 0##,l #) -> integerFromWordNeg# l
+ (# h ,l #) -> IN (bigNatFromWord2# h l)
+
+ (# True, True #) -> case timesWord2# (int2Word# x)
+ (int2Word# y) of
+ (# 0##,l #) -> integerFromWord# l
+ (# h ,l #) -> IP (bigNatFromWord2# h l)
+#else
+integerMul (IS x) (IS y) = case timesInt2# x y of
+ (# 0#, _h, l #) -> IS l
+ (# _ , h, l #)
+ | isTrue# (h >=# 0#)
+ -> IP (bigNatFromWord2# (int2Word# h) (int2Word# l))
+ | True
+ -> let
+ -- two's complement of a two-word negative Int:
+ -- l' = complement l + 1
+ -- h' = complement h + carry
+ !(# l',c #) = addWordC# (not# (int2Word# l)) 1##
+ !h' = int2Word# c `plusWord#` not# (int2Word# h)
+ in IN (bigNatFromWord2# h' l')
+#endif
+integerMul x@(IS _) y = integerMul y x
+integerMul (IP x) (IP y) = IP (bigNatMul x y)
+integerMul (IP x) (IN y) = IN (bigNatMul x y)
+integerMul (IP x) (IS y)
+ | isTrue# (y >=# 0#) = IP (bigNatMulWord# x (int2Word# y))
+ | True = IN (bigNatMulWord# x (int2Word# (negateInt# y)))
+integerMul (IN x) (IN y) = IP (bigNatMul x y)
+integerMul (IN x) (IP y) = IN (bigNatMul x y)
+integerMul (IN x) (IS y)
+ | isTrue# (y >=# 0#) = IN (bigNatMulWord# x (int2Word# y))
+ | True = IP (bigNatMulWord# x (int2Word# (negateInt# y)))
+
+-- | Negate 'Integer'.
+--
+-- One edge-case issue to take into account is that Int's range is not
+-- symmetric around 0. I.e. @minBound+maxBound = -1@
+--
+-- IP is used iff n > maxBound::Int
+-- IN is used iff n < minBound::Int
+integerNegate :: Integer -> Integer
+{-# NOINLINE integerNegate #-}
+integerNegate (IN b) = IP b
+integerNegate (IS INT_MINBOUND#) = IP (bigNatFromWord# ABS_INT_MINBOUND##)
+integerNegate (IS i) = IS (negateInt# i)
+integerNegate (IP b)
+ | isTrue# (bigNatEqWord# b ABS_INT_MINBOUND##) = IS INT_MINBOUND#
+ | True = IN b
+
+
+-- | Compute absolute value of an 'Integer'
+integerAbs :: Integer -> Integer
+{-# NOINLINE integerAbs #-}
+integerAbs (IN i) = IP i
+integerAbs n@(IP _) = n
+integerAbs n@(IS i)
+ | isTrue# (i >=# 0#) = n
+ | INT_MINBOUND# <- i = IP (bigNatFromWord# ABS_INT_MINBOUND##)
+ | True = IS (negateInt# i)
+
+
+-- | Return @-1@, @0@, and @1@ depending on whether argument is
+-- negative, zero, or positive, respectively
+integerSignum :: Integer -> Integer
+{-# NOINLINE integerSignum #-}
+integerSignum !j = IS (integerSignum# j)
+
+-- | Return @-1#@, @0#@, and @1#@ depending on whether argument is
+-- negative, zero, or positive, respectively
+integerSignum# :: Integer -> Int#
+{-# NOINLINE integerSignum# #-}
+integerSignum# (IN _) = -1#
+integerSignum# (IS i#) = sgnI# i#
+integerSignum# (IP _ ) = 1#
+
+-- | Count number of set bits. For negative arguments returns
+-- the negated population count of the absolute value.
+integerPopCount# :: Integer -> Int#
+{-# NOINLINE integerPopCount# #-}
+integerPopCount# (IS i)
+ | isTrue# (i >=# 0#) = word2Int# (popCntI# i)
+ | True = negateInt# (word2Int# (popCntI# (negateInt# i)))
+integerPopCount# (IP bn) = word2Int# (bigNatPopCount# bn)
+integerPopCount# (IN bn) = negateInt# (word2Int# (bigNatPopCount# bn))
+
+-- | Positive 'Integer' for which only /n/-th bit is set
+integerBit# :: Word# -> Integer
+{-# NOINLINE integerBit# #-}
+integerBit# i
+ | isTrue# (i `ltWord#` (WORD_SIZE_IN_BITS## `minusWord#` 1##))
+ = IS (uncheckedIShiftL# 1# (word2Int# i))
+
+ | True = IP (bigNatBit# i)
+
+-- | 'Integer' for which only /n/-th bit is set
+integerBit :: Word -> Integer
+integerBit (W# i) = integerBit# i
+
+-- | Test if /n/-th bit is set.
+--
+-- Fake 2's complement for negative values (might be slow)
+integerTestBit# :: Integer -> Word# -> Bool#
+{-# NOINLINE integerTestBit# #-}
+integerTestBit# (IS x) i
+ | isTrue# (i `ltWord#` WORD_SIZE_IN_BITS##)
+ = testBitI# x i
+ | True
+ = x <# 0#
+integerTestBit# (IP x) i = bigNatTestBit# x i
+integerTestBit# (IN x) i
+ | isTrue# (iw >=# n)
+ = 1#
+ -- if all the limbs j with j < iw are null, then we have to consider the
+ -- carry of the 2's complement convertion. Otherwise we just have to return
+ -- the inverse of the bit test
+ | allZ iw = testBitW# (xi `minusWord#` 1##) ib ==# 0#
+ | True = testBitW# xi ib ==# 0#
+ where
+ !xi = bigNatIndex# x iw
+ !n = bigNatSize# x
+ !iw = word2Int# (i `uncheckedShiftRL#` WORD_SIZE_BITS_SHIFT#)
+ !ib = i `and#` WORD_SIZE_BITS_MASK##
+
+ allZ 0# = True
+ allZ j | isTrue# (bigNatIndex# x (j -# 1#) `eqWord#` 0##) = allZ (j -# 1#)
+ | True = False
+
+-- | Test if /n/-th bit is set. For negative Integers it tests the n-th bit of
+-- the negated argument.
+--
+-- Fake 2's complement for negative values (might be slow)
+integerTestBit :: Integer -> Word -> Bool
+integerTestBit !i (W# n) = isTrue# (integerTestBit# i n)
+
+-- | Shift-right operation
+--
+-- Fake 2's complement for negative values (might be slow)
+integerShiftR# :: Integer -> Word# -> Integer
+{-# NOINLINE integerShiftR# #-}
+integerShiftR# !x 0## = x
+integerShiftR# (IS i) n = IS (iShiftRA# i (word2Int# n))
+ where
+ iShiftRA# a b
+ | isTrue# (b >=# WORD_SIZE_IN_BITS#) = (a <# 0#) *# (-1#)
+ | True = a `uncheckedIShiftRA#` b
+integerShiftR# (IP bn) n = integerFromBigNat (bigNatShiftR# bn n)
+integerShiftR# (IN bn) n =
+ case integerFromBigNatNeg (bigNatShiftRNeg# bn n) of
+ IS 0# -> IS -1#
+ r -> r
+
+-- | Shift-right operation
+--
+-- Fake 2's complement for negative values (might be slow)
+integerShiftR :: Integer -> Word -> Integer
+integerShiftR !x (W# w) = integerShiftR# x w
+
+-- | Shift-left operation
+integerShiftL# :: Integer -> Word# -> Integer
+{-# NOINLINE integerShiftL# #-}
+integerShiftL# !x 0## = x
+integerShiftL# (IS 0#) _ = IS 0#
+integerShiftL# (IS 1#) n = integerBit# n
+integerShiftL# (IS i) n
+ | isTrue# (i >=# 0#) = integerFromBigNat (bigNatShiftL# (bigNatFromWord# (int2Word# i)) n)
+ | True = integerFromBigNatNeg (bigNatShiftL# (bigNatFromWord# (int2Word# (negateInt# i))) n)
+integerShiftL# (IP bn) n = IP (bigNatShiftL# bn n)
+integerShiftL# (IN bn) n = IN (bigNatShiftL# bn n)
+
+-- | Shift-left operation
+--
+-- Remember that bits are stored in sign-magnitude form, hence the behavior of
+-- negative Integers is different from negative Int's behavior.
+integerShiftL :: Integer -> Word -> Integer
+integerShiftL !x (W# w) = integerShiftL# x w
+
+-- | Bitwise OR operation
+--
+-- Fake 2's complement for negative values (might be slow)
+integerOr :: Integer -> Integer -> Integer
+{-# NOINLINE integerOr #-}
+integerOr a b = case a of
+ IS 0# -> b
+ IS -1# -> IS -1#
+ IS x -> case b of
+ IS 0# -> a
+ IS -1# -> IS -1#
+ IS y -> IS (orI# x y)
+ IP y
+ | isTrue# (x >=# 0#) -> integerFromBigNat (bigNatOrWord# y (int2Word# x))
+ | True -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatAndNot -- use De Morgan's laws
+ (bigNatFromWord#
+ (int2Word# (negateInt# x) `minusWord#` 1##))
+ y)
+ 1##)
+ IN y
+ | isTrue# (x >=# 0#) -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatAndNotWord# -- use De Morgan's laws
+ (bigNatSubWordUnsafe# y 1##)
+ (int2Word# x))
+ 1##)
+ | True -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatAndWord# -- use De Morgan's laws
+ (bigNatSubWordUnsafe# y 1##)
+ (int2Word# (negateInt# x) `minusWord#` 1##))
+ 1##)
+ IP x -> case b of
+ IS _ -> integerOr b a
+ IP y -> integerFromBigNat (bigNatOr x y)
+ IN y -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatAndNot -- use De Morgan's laws
+ (bigNatSubWordUnsafe# y 1##)
+ x)
+ 1##)
+ IN x -> case b of
+ IS _ -> integerOr b a
+ IN y -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatAnd -- use De Morgan's laws
+ (bigNatSubWordUnsafe# x 1##)
+ (bigNatSubWordUnsafe# y 1##))
+ 1##)
+ IP y -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatAndNot -- use De Morgan's laws
+ (bigNatSubWordUnsafe# x 1##)
+ y)
+ 1##)
+
+
+-- | Bitwise XOR operation
+--
+-- Fake 2's complement for negative values (might be slow)
+integerXor :: Integer -> Integer -> Integer
+{-# NOINLINE integerXor #-}
+integerXor a b = case a of
+ IS 0# -> b
+ IS -1# -> integerComplement b
+ IS x -> case b of
+ IS 0# -> a
+ IS -1# -> integerComplement a
+ IS y -> IS (xorI# x y)
+ IP y
+ | isTrue# (x >=# 0#) -> integerFromBigNat (bigNatXorWord# y (int2Word# x))
+ | True -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatXorWord#
+ y
+ (int2Word# (negateInt# x) `minusWord#` 1##))
+ 1##)
+ IN y
+ | isTrue# (x >=# 0#) -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatXorWord#
+ (bigNatSubWordUnsafe# y 1##)
+ (int2Word# x))
+ 1##)
+ | True -> integerFromBigNat
+ (bigNatXorWord# -- xor (not x) (not y) = xor x y
+ (bigNatSubWordUnsafe# y 1##)
+ (int2Word# (negateInt# x) `minusWord#` 1##))
+ IP x -> case b of
+ IS _ -> integerXor b a
+ IP y -> integerFromBigNat (bigNatXor x y)
+ IN y -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatXor
+ x
+ (bigNatSubWordUnsafe# y 1##))
+ 1##)
+ IN x -> case b of
+ IS _ -> integerXor b a
+ IN y -> integerFromBigNat
+ (bigNatXor -- xor (not x) (not y) = xor x y
+ (bigNatSubWordUnsafe# x 1##)
+ (bigNatSubWordUnsafe# y 1##))
+ IP y -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatXor
+ y
+ (bigNatSubWordUnsafe# x 1##))
+ 1##)
+
+
+
+-- | Bitwise AND operation
+--
+-- Fake 2's complement for negative values (might be slow)
+integerAnd :: Integer -> Integer -> Integer
+{-# NOINLINE integerAnd #-}
+integerAnd a b = case a of
+ IS 0# -> IS 0#
+ IS -1# -> b
+ IS x -> case b of
+ IS 0# -> IS 0#
+ IS -1# -> a
+ IS y -> IS (andI# x y)
+ IP y -> integerFromBigNat (bigNatAndInt# y x)
+ IN y
+ | isTrue# (x >=# 0#) -> integerFromWord# (int2Word# x `andNot#` (indexWordArray# y 0# `minusWord#` 1##))
+ | True -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatOrWord# -- use De Morgan's laws
+ (bigNatSubWordUnsafe# y 1##)
+ (wordFromAbsInt# x `minusWord#` 1##))
+ 1##)
+ IP x -> case b of
+ IS _ -> integerAnd b a
+ IP y -> integerFromBigNat (bigNatAnd x y)
+ IN y -> integerFromBigNat (bigNatAndNot x (bigNatSubWordUnsafe# y 1##))
+ IN x -> case b of
+ IS _ -> integerAnd b a
+ IN y -> integerFromBigNatNeg
+ (bigNatAddWord#
+ (bigNatOr -- use De Morgan's laws
+ (bigNatSubWordUnsafe# x 1##)
+ (bigNatSubWordUnsafe# y 1##))
+ 1##)
+ IP y -> integerFromBigNat (bigNatAndNot y (bigNatSubWordUnsafe# x 1##))
+
+
+
+-- | Binary complement of the
+integerComplement :: Integer -> Integer
+{-# NOINLINE integerComplement #-}
+integerComplement (IS x) = IS (notI# x)
+integerComplement (IP x) = IN (bigNatAddWord# x 1##)
+integerComplement (IN x) = IP (bigNatSubWordUnsafe# x 1##)
+
+
+-- | Simultaneous 'integerQuot' and 'integerRem'.
+--
+-- Divisor must be non-zero otherwise the GHC runtime will terminate
+-- with a division-by-zero fault.
+integerQuotRem# :: Integer -> Integer -> (# Integer, Integer #)
+{-# NOINLINE integerQuotRem# #-}
+integerQuotRem# !n (IS 1#) = (# n, IS 0# #)
+integerQuotRem# !n (IS -1#) = let !q = integerNegate n in (# q, (IS 0#) #)
+integerQuotRem# !_ (IS 0#) = (# divByZero, divByZero #)
+integerQuotRem# (IS 0#) _ = (# IS 0#, IS 0# #)
+integerQuotRem# (IS n#) (IS d#) = case quotRemInt# n# d# of
+ (# q#, r# #) -> (# IS q#, IS r# #)
+integerQuotRem# (IP n) (IP d) = case bigNatQuotRem# n d of
+ (# q, r #) -> (# integerFromBigNat q, integerFromBigNat r #)
+integerQuotRem# (IP n) (IN d) = case bigNatQuotRem# n d of
+ (# q, r #) -> (# integerFromBigNatNeg q, integerFromBigNat r #)
+integerQuotRem# (IN n) (IN d) = case bigNatQuotRem# n d of
+ (# q, r #) -> (# integerFromBigNat q, integerFromBigNatNeg r #)
+integerQuotRem# (IN n) (IP d) = case bigNatQuotRem# n d of
+ (# q, r #) -> (# integerFromBigNatNeg q, integerFromBigNatNeg r #)
+integerQuotRem# (IP n) (IS d#)
+ | isTrue# (d# >=# 0#) = case bigNatQuotRemWord# n (int2Word# d#) of
+ (# q, r# #) -> (# integerFromBigNat q, integerFromWord# r# #)
+ | True = case bigNatQuotRemWord# n (int2Word# (negateInt# d#)) of
+ (# q, r# #) -> (# integerFromBigNatNeg q, integerFromWord# r# #)
+integerQuotRem# (IN n) (IS d#)
+ | isTrue# (d# >=# 0#) = case bigNatQuotRemWord# n (int2Word# d#) of
+ (# q, r# #) -> (# integerFromBigNatNeg q, integerFromWordNeg# r# #)
+ | True = case bigNatQuotRemWord# n (int2Word# (negateInt# d#)) of
+ (# q, r# #) -> (# integerFromBigNat q, integerFromWordNeg# r# #)
+integerQuotRem# n@(IS _) (IN _) = (# IS 0#, n #) -- since @n < d@
+integerQuotRem# n@(IS n#) (IP d) -- need to account for (IS minBound)
+ | isTrue# (n# ># 0#) = (# IS 0#, n #)
+ | isTrue# (bigNatGtWord# d (int2Word# (negateInt# n#))) = (# IS 0#, n #)
+ | True {- abs(n) == d -} = (# IS -1#, IS 0# #)
+
+-- | Simultaneous 'integerQuot' and 'integerRem'.
+--
+-- Divisor must be non-zero otherwise the GHC runtime will terminate
+-- with a division-by-zero fault.
+integerQuotRem :: Integer -> Integer -> (Integer, Integer)
+integerQuotRem !x !y = case integerQuotRem# x y of
+ (# q, r #) -> (q, r)
+
+
+integerQuot :: Integer -> Integer -> Integer
+{-# NOINLINE integerQuot #-}
+integerQuot !n (IS 1#) = n
+integerQuot !n (IS -1#) = integerNegate n
+integerQuot !_ (IS 0#) = divByZero
+integerQuot (IS 0#) _ = IS 0#
+integerQuot (IS n#) (IS d#) = IS (quotInt# n# d#)
+integerQuot (IP n) (IS d#)
+ | isTrue# (d# >=# 0#) = integerFromBigNat (bigNatQuotWord# n (int2Word# d#))
+ | True = integerFromBigNatNeg (bigNatQuotWord# n
+ (int2Word# (negateInt# d#)))
+integerQuot (IN n) (IS d#)
+ | isTrue# (d# >=# 0#) = integerFromBigNatNeg (bigNatQuotWord# n (int2Word# d#))
+ | True = integerFromBigNat (bigNatQuotWord# n
+ (int2Word# (negateInt# d#)))
+integerQuot (IP n) (IP d) = integerFromBigNat (bigNatQuot n d)
+integerQuot (IP n) (IN d) = integerFromBigNatNeg (bigNatQuot n d)
+integerQuot (IN n) (IP d) = integerFromBigNatNeg (bigNatQuot n d)
+integerQuot (IN n) (IN d) = integerFromBigNat (bigNatQuot n d)
+integerQuot n d = case integerQuotRem# n d of (# q, _ #) -> q
+
+integerRem :: Integer -> Integer -> Integer
+{-# NOINLINE integerRem #-}
+integerRem !_ (IS 1#) = IS 0#
+integerRem _ (IS -1#) = IS 0#
+integerRem _ (IS 0#) = IS (remInt# 0# 0#)
+integerRem (IS 0#) _ = IS 0#
+integerRem (IS n#) (IS d#) = IS (remInt# n# d#)
+integerRem (IP n) (IS d#)
+ = integerFromWord# (bigNatRemWord# n (int2Word# (absI# d#)))
+integerRem (IN n) (IS d#)
+ = integerFromWordNeg# (bigNatRemWord# n (int2Word# (absI# d#)))
+integerRem (IP n) (IP d) = integerFromBigNat (bigNatRem n d)
+integerRem (IP n) (IN d) = integerFromBigNat (bigNatRem n d)
+integerRem (IN n) (IP d) = integerFromBigNatNeg (bigNatRem n d)
+integerRem (IN n) (IN d) = integerFromBigNatNeg (bigNatRem n d)
+integerRem n d = case integerQuotRem# n d of (# _, r #) -> r
+
+
+-- | Simultaneous 'integerDiv' and 'integerMod'.
+--
+-- Divisor must be non-zero otherwise the GHC runtime will terminate
+-- with a division-by-zero fault.
+integerDivMod# :: Integer -> Integer -> (# Integer, Integer #)
+{-# NOINLINE integerDivMod# #-}
+integerDivMod# !n !d
+ | isTrue# (integerSignum# r ==# negateInt# (integerSignum# d))
+ = let !q' = integerAdd q (IS -1#) -- TODO: optimize
+ !r' = integerAdd r d
+ in (# q', r' #)
+ | True = qr
+ where
+ !qr@(# q, r #) = integerQuotRem# n d
+
+-- | Simultaneous 'integerDiv' and 'integerMod'.
+--
+-- Divisor must be non-zero otherwise the GHC runtime will terminate
+-- with a division-by-zero fault.
+integerDivMod :: Integer -> Integer -> (Integer, Integer)
+integerDivMod !n !d = case integerDivMod# n d of
+ (# q,r #) -> (q,r)
+
+
+integerDiv :: Integer -> Integer -> Integer
+{-# NOINLINE integerDiv #-}
+integerDiv !n !d
+ -- same-sign ops can be handled by more efficient 'integerQuot'
+ | isTrue# (integerIsNegative# n ==# integerIsNegative# d) = integerQuot n d
+ | True = case integerDivMod# n d of (# q, _ #) -> q
+
+
+integerMod :: Integer -> Integer -> Integer
+{-# NOINLINE integerMod #-}
+integerMod !n !d
+ -- same-sign ops can be handled by more efficient 'integerRem'
+ | isTrue# (integerIsNegative# n ==# integerIsNegative# d) = integerRem n d
+ | True = case integerDivMod# n d of (# _, r #) -> r
+
+-- | Compute greatest common divisor.
+integerGcd :: Integer -> Integer -> Integer
+{-# NOINLINE integerGcd #-}
+integerGcd (IS 0#) !b = integerAbs b
+integerGcd a (IS 0#) = integerAbs a
+integerGcd (IS 1#) _ = IS 1#
+integerGcd (IS -1#) _ = IS 1#
+integerGcd _ (IS 1#) = IS 1#
+integerGcd _ (IS -1#) = IS 1#
+integerGcd (IS a) (IS b) = integerFromWord# (gcdWord#
+ (int2Word# (absI# a))
+ (int2Word# (absI# b)))
+integerGcd a@(IS _) b = integerGcd b a
+integerGcd (IN a) b = integerGcd (IP a) b
+integerGcd (IP a) (IP b) = integerFromBigNat (bigNatGcd a b)
+integerGcd (IP a) (IN b) = integerFromBigNat (bigNatGcd a b)
+integerGcd (IP a) (IS b) = integerFromWord# (bigNatGcdWord# a (int2Word# (absI# b)))
+
+-- | Compute least common multiple.
+integerLcm :: Integer -> Integer -> Integer
+{-# NOINLINE integerLcm #-}
+integerLcm (IS 0#) !_ = IS 0#
+integerLcm (IS 1#) b = integerAbs b
+integerLcm (IS -1#) b = integerAbs b
+integerLcm _ (IS 0#) = IS 0#
+integerLcm a (IS 1#) = integerAbs a
+integerLcm a (IS -1#) = integerAbs a
+integerLcm a b = (aa `integerQuot` (aa `integerGcd` ab)) `integerMul` ab
+ where -- TODO: use extended GCD to get a's factor directly
+ aa = integerAbs a
+ ab = integerAbs b
+
+-- | Square a Integer
+integerSqr :: Integer -> Integer
+integerSqr !a = integerMul a a
+
+
+-- | Base 2 logarithm (floor)
+--
+-- For numbers <= 0, return 0
+integerLog2# :: Integer -> Word#
+integerLog2# (IS i)
+ | isTrue# (i <=# 0#) = 0##
+ | True = wordLog2# (int2Word# i)
+integerLog2# (IN _) = 0##
+integerLog2# (IP b) = bigNatLog2# b
+
+-- | Base 2 logarithm (floor)
+--
+-- For numbers <= 0, return 0
+integerLog2 :: Integer -> Word
+integerLog2 !i = W# (integerLog2# i)
+
+-- | Logarithm (floor) for an arbitrary base
+--
+-- For numbers <= 0, return 0
+integerLogBaseWord# :: Word# -> Integer -> Word#
+integerLogBaseWord# base !i
+ | integerIsNegative i = 0##
+ | True = naturalLogBaseWord# base (integerToNatural i)
+
+-- | Logarithm (floor) for an arbitrary base
+--
+-- For numbers <= 0, return 0
+integerLogBaseWord :: Word -> Integer -> Word
+integerLogBaseWord (W# base) !i = W# (integerLogBaseWord# base i)
+
+-- | Logarithm (floor) for an arbitrary base
+--
+-- For numbers <= 0, return 0
+integerLogBase# :: Integer -> Integer -> Word#
+integerLogBase# !base !i
+ | integerIsNegative i = 0##
+ | True = naturalLogBase# (integerToNatural base)
+ (integerToNatural i)
+
+-- | Logarithm (floor) for an arbitrary base
+--
+-- For numbers <= 0, return 0
+integerLogBase :: Integer -> Integer -> Word
+integerLogBase !base !i = W# (integerLogBase# base i)
+
+-- | Indicate if the value is a power of two and which one
+integerIsPowerOf2# :: Integer -> (# () | Word# #)
+integerIsPowerOf2# (IS i)
+ | isTrue# (i <=# 0#) = (# () | #)
+ | True = wordIsPowerOf2# (int2Word# i)
+integerIsPowerOf2# (IN _) = (# () | #)
+integerIsPowerOf2# (IP w) = bigNatIsPowerOf2# w
+
+#if WORD_SIZE_IN_BITS == 32
+
+-- | Convert an Int64# into an Integer on 32-bit architectures
+integerFromInt64# :: Int64# -> Integer
+{-# NOINLINE integerFromInt64# #-}
+integerFromInt64# !i
+ | isTrue# ((i `leInt64#` intToInt64# 0x7FFFFFFF#)
+ &&# (i `geInt64#` intToInt64# -0x80000000#))
+ = IS (int64ToInt# i)
+
+ | isTrue# (i `geInt64#` intToInt64# 0#)
+ = IP (bigNatFromWord64# (int64ToWord64# i))
+
+ | True
+ = IN (bigNatFromWord64# (int64ToWord64# (negateInt64# i)))
+
+-- | Convert a Word64# into an Integer on 32-bit architectures
+integerFromWord64# :: Word64# -> Integer
+{-# NOINLINE integerFromWord64# #-}
+integerFromWord64# !w
+ | isTrue# (w `leWord64#` wordToWord64# 0x7FFFFFFF##)
+ = IS (int64ToInt# (word64ToInt64# w))
+ | True
+ = IP (bigNatFromWord64# w)
+
+-- | Convert an Integer into an Int64# on 32-bit architectures
+integerToInt64# :: Integer -> Int64#
+{-# NOINLINE integerToInt64# #-}
+integerToInt64# (IS i) = intToInt64# i
+integerToInt64# (IP b) = word64ToInt64# (bigNatToWord64# b)
+integerToInt64# (IN b) = negateInt64# (word64ToInt64# (bigNatToWord64# b))
+
+-- | Convert an Integer into a Word64# on 32-bit architectures
+integerToWord64# :: Integer -> Word64#
+{-# NOINLINE integerToWord64# #-}
+integerToWord64# (IS i) = int64ToWord64# (intToInt64# i)
+integerToWord64# (IP b) = bigNatToWord64# b
+integerToWord64# (IN b) = int64ToWord64# (negateInt64# (word64ToInt64# (bigNatToWord64# b)))
+
+#else
+
+-- | Convert an Int64# into an Integer on 64-bit architectures
+integerFromInt64# :: Int# -> Integer
+integerFromInt64# !x = IS x
+
+#endif
+
+----------------------------------------------------------------------------
+-- Conversions to/from floating point
+----------------------------------------------------------------------------
+
+-- | Decode a Double# into (# Integer mantissa, Int# exponent #)
+integerDecodeDouble# :: Double# -> (# Integer, Int# #)
+{-# NOINLINE integerDecodeDouble# #-}
+integerDecodeDouble# !x = case decodeDouble_Int64# x of
+ (# m, e #) -> (# integerFromInt64# m, e #)
+
+-- | Decode a Double# into (# Integer mantissa, Int# exponent #)
+integerDecodeDouble :: Double -> (Integer, Int)
+integerDecodeDouble (D# x) = case integerDecodeDouble# x of
+ (# m, e #) -> (m, I# e)
+
+-- | Encode (# Integer mantissa, Int# exponent #) into a Double#
+integerEncodeDouble# :: Integer -> Int# -> Double#
+{-# NOINLINE integerEncodeDouble# #-}
+integerEncodeDouble# (IS i) 0# = int2Double# i
+integerEncodeDouble# (IS i) e = intEncodeDouble# i e
+integerEncodeDouble# (IP b) e = bigNatEncodeDouble# b e
+integerEncodeDouble# (IN b) e = negateDouble# (bigNatEncodeDouble# b e)
+
+-- | Encode (Integer mantissa, Int exponent) into a Double
+integerEncodeDouble :: Integer -> Int -> Double
+integerEncodeDouble !m (I# e) = D# (integerEncodeDouble# m e)
+
+-- | Encode an Integer (mantissa) into a Double#
+integerToDouble# :: Integer -> Double#
+{-# NOINLINE integerToDouble# #-}
+integerToDouble# !i = integerEncodeDouble# i 0#
+
+-- | Encode an Integer (mantissa) into a Float#
+integerToFloat# :: Integer -> Float#
+{-# NOINLINE integerToFloat# #-}
+integerToFloat# !i = integerEncodeFloat# i 0#
+
+-- | Encode (# Integer mantissa, Int# exponent #) into a Float#
+--
+-- TODO: Not sure if it's worth to write 'Float' optimized versions here
+integerEncodeFloat# :: Integer -> Int# -> Float#
+{-# NOINLINE integerEncodeFloat# #-}
+integerEncodeFloat# !m 0# = double2Float# (integerToDouble# m)
+integerEncodeFloat# !m e = double2Float# (integerEncodeDouble# m e)
+
+-- | Compute the number of digits of the Integer (without the sign) in the given base.
+--
+-- `base` must be > 1
+integerSizeInBase# :: Word# -> Integer -> Word#
+integerSizeInBase# base (IS i) = wordSizeInBase# base (int2Word# (absI# i))
+integerSizeInBase# base (IP n) = bigNatSizeInBase# base n
+integerSizeInBase# base (IN n) = bigNatSizeInBase# base n
+
+-- | Write an 'Integer' (without sign) to @/addr/@ in base-256 representation
+-- and return the number of bytes written.
+--
+-- The endianness is selected with the Bool# parameter: write most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+integerToAddr# :: Integer -> Addr# -> Bool# -> State# s -> (# State# s, Word# #)
+integerToAddr# (IS i) = wordToAddr# (int2Word# (absI# i))
+integerToAddr# (IP n) = bigNatToAddr# n
+integerToAddr# (IN n) = bigNatToAddr# n
+
+-- | Write an 'Integer' (without sign) to @/addr/@ in base-256 representation
+-- and return the number of bytes written.
+--
+-- The endianness is selected with the Bool# parameter: write most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+integerToAddr :: Integer -> Addr# -> Bool# -> IO Word
+integerToAddr a addr e = IO \s -> case integerToAddr# a addr e s of
+ (# s', w #) -> (# s', W# w #)
+
+-- | Read an 'Integer' (without sign) in base-256 representation from an Addr#.
+--
+-- The size is given in bytes.
+--
+-- The endianness is selected with the Bool# parameter: most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+--
+-- Null higher limbs are automatically trimed.
+integerFromAddr# :: Word# -> Addr# -> Bool# -> State# s -> (# State# s, Integer #)
+integerFromAddr# sz addr e s =
+ case bigNatFromAddr# sz addr e s of
+ (# s', n #) -> (# s', integerFromBigNat n #)
+
+-- | Read an 'Integer' (without sign) in base-256 representation from an Addr#.
+--
+-- The size is given in bytes.
+--
+-- The endianness is selected with the Bool# parameter: most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+--
+-- Null higher limbs are automatically trimed.
+integerFromAddr :: Word# -> Addr# -> Bool# -> IO Integer
+integerFromAddr sz addr e = IO (integerFromAddr# sz addr e)
+
+
+
+-- | Write an 'Integer' (without sign) in base-256 representation and return the
+-- number of bytes written.
+--
+-- The endianness is selected with the Bool# parameter: most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+integerToMutableByteArray# :: Integer -> MutableByteArray# s -> Word# -> Bool# -> State# s -> (# State# s, Word# #)
+integerToMutableByteArray# (IS i) = wordToMutableByteArray# (int2Word# (absI# i))
+integerToMutableByteArray# (IP a) = bigNatToMutableByteArray# a
+integerToMutableByteArray# (IN a) = bigNatToMutableByteArray# a
+
+-- | Write an 'Integer' (without sign) in base-256 representation and return the
+-- number of bytes written.
+--
+-- The endianness is selected with the Bool# parameter: most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+integerToMutableByteArray :: Integer -> MutableByteArray# RealWorld -> Word# -> Bool# -> IO Word
+integerToMutableByteArray i mba w e = IO \s -> case integerToMutableByteArray# i mba w e s of
+ (# s', r #) -> (# s', W# r #)
+
+-- | Read an 'Integer' (without sign) in base-256 representation from a ByteArray#.
+--
+-- The size is given in bytes.
+--
+-- The endianness is selected with the Bool# parameter: most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+--
+-- Null higher limbs are automatically trimed.
+integerFromByteArray# :: Word# -> ByteArray# -> Word# -> Bool# -> State# s -> (# State# s, Integer #)
+integerFromByteArray# sz ba off e s = case bigNatFromByteArray# sz ba off e s of
+ (# s', a #) -> (# s', integerFromBigNat a #)
+
+-- | Read an 'Integer' (without sign) in base-256 representation from a ByteArray#.
+--
+-- The size is given in bytes.
+--
+-- The endianness is selected with the Bool# parameter: most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+--
+-- Null higher limbs are automatically trimed.
+integerFromByteArray :: Word# -> ByteArray# -> Word# -> Bool# -> Integer
+integerFromByteArray sz ba off e = case runRW# (integerFromByteArray# sz ba off e) of
+ (# _, i #) -> i