summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/Natural.hs
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/GHC/Natural.hs')
-rw-r--r--libraries/base/GHC/Natural.hs792
1 files changed, 368 insertions, 424 deletions
diff --git a/libraries/base/GHC/Natural.hs b/libraries/base/GHC/Natural.hs
index 0e5abc77bc..71511d37b3 100644
--- a/libraries/base/GHC/Natural.hs
+++ b/libraries/base/GHC/Natural.hs
@@ -1,12 +1,8 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
-{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE UnboxedTuples #-}
-{-# LANGUAGE Unsafe #-}
-
-{-# OPTIONS_HADDOCK not-home #-}
-----------------------------------------------------------------------------
-- |
@@ -34,44 +30,76 @@ module GHC.Natural
-- (i.e. which constructors are available) depends on the
-- 'Integer' backend used!
Natural(..)
+ , mkNatural
, isValidNatural
+ -- * Arithmetic
+ , plusNatural
+ , minusNatural
+ , minusNaturalMaybe
+ , timesNatural
+ , negateNatural
+ , signumNatural
+ , quotRemNatural
+ , quotNatural
+ , remNatural
+#if defined(MIN_VERSION_integer_gmp)
+ , gcdNatural
+ , lcmNatural
+#endif
+ -- * Bits
+ , andNatural
+ , orNatural
+ , xorNatural
+ , bitNatural
+ , testBitNatural
+#if defined(MIN_VERSION_integer_gmp)
+ , popCountNatural
+#endif
+ , shiftLNatural
+ , shiftRNatural
-- * Conversions
+ , naturalToInteger
+ , naturalToWord
+ , naturalToInt
, naturalFromInteger
, wordToNatural
+ , intToNatural
, naturalToWordMaybe
- -- * Checked subtraction
- , minusNaturalMaybe
+ , wordToNatural#
+ , wordToNaturalBase
-- * Modular arithmetic
, powModNatural
) where
#include "MachDeps.h"
+import GHC.Classes
+import GHC.Maybe
+import GHC.Types
+import GHC.Prim
+import {-# SOURCE #-} GHC.Exception.Type (underflowException, divZeroException)
#if defined(MIN_VERSION_integer_gmp)
-# define HAVE_GMP_BIGNAT MIN_VERSION_integer_gmp(1,0,0)
-#else
-# define HAVE_GMP_BIGNAT 0
-#endif
-
-import GHC.Arr
-import GHC.Base
-import {-# SOURCE #-} GHC.Exception (underflowException)
-#if HAVE_GMP_BIGNAT
import GHC.Integer.GMP.Internals
-import Data.Word
-import Data.Int
+#else
+import GHC.Integer
#endif
-import GHC.Num
-import GHC.Real
-import GHC.Read
-import GHC.Show
-import GHC.Enum
-import GHC.List
-
-import Data.Bits
default ()
+-- Most high-level operations need to be marked `NOINLINE` as
+-- otherwise GHC doesn't recognize them and fails to apply constant
+-- folding to `Natural`-typed expression.
+--
+-- To this end, the CPP hack below allows to write the pseudo-pragma
+--
+-- {-# CONSTANT_FOLDED plusNatural #-}
+--
+-- which is simply expanded into a
+--
+-- {-# NOINLINE plusNatural #-}
+--
+#define CONSTANT_FOLDED NOINLINE
+
-------------------------------------------------------------------------------
-- Arithmetic underflow
-------------------------------------------------------------------------------
@@ -83,17 +111,27 @@ default ()
underflowError :: a
underflowError = raise# underflowException
+{-# NOINLINE divZeroError #-}
+divZeroError :: a
+divZeroError = raise# divZeroException
+
-------------------------------------------------------------------------------
-- Natural type
-------------------------------------------------------------------------------
-#if HAVE_GMP_BIGNAT
+#if defined(MIN_VERSION_integer_gmp)
-- TODO: if saturated arithmetic is to used, replace 'underflowError' by '0'
-- | Type representing arbitrary-precision non-negative integers.
--
--- Operations whose result would be negative
--- @'throw' ('Underflow' :: 'ArithException')@.
+-- >>> 2^100 :: Natural
+-- 1267650600228229401496703205376
+--
+-- Operations whose result would be negative @'Control.Exception.throw'
+-- ('Control.Exception.Underflow' :: 'Control.Exception.ArithException')@,
+--
+-- >>> -1 :: Natural
+-- *** Exception: arithmetic underflow
--
-- @since 4.8.0.0
data Natural = NatS# GmpLimb# -- ^ in @[0, maxBound::Word]@
@@ -102,8 +140,12 @@ data Natural = NatS# GmpLimb# -- ^ in @[0, maxBound::Word]@
-- __Invariant__: 'NatJ#' is used
-- /iff/ value doesn't fit in
-- 'NatS#' constructor.
- deriving (Eq,Ord) -- NB: Order of constructors *must*
+ -- NB: Order of constructors *must*
-- coincide with 'Ord' relation
+ deriving ( Eq -- ^ @since 4.8.0.0
+ , Ord -- ^ @since 4.8.0.0
+ )
+
-- | Test whether all internal invariants are satisfied by 'Natural' value
--
@@ -114,107 +156,32 @@ data Natural = NatS# GmpLimb# -- ^ in @[0, maxBound::Word]@
isValidNatural :: Natural -> Bool
isValidNatural (NatS# _) = True
isValidNatural (NatJ# bn) = isTrue# (isValidBigNat# bn)
- && I# (sizeofBigNat# bn) > 0
-
-{-# RULES
-"fromIntegral/Natural->Natural" fromIntegral = id :: Natural -> Natural
-"fromIntegral/Natural->Integer" fromIntegral = toInteger :: Natural->Integer
-"fromIntegral/Natural->Word" fromIntegral = naturalToWord
-"fromIntegral/Natural->Word8"
- fromIntegral = (fromIntegral :: Word -> Word8) . naturalToWord
-"fromIntegral/Natural->Word16"
- fromIntegral = (fromIntegral :: Word -> Word16) . naturalToWord
-"fromIntegral/Natural->Word32"
- fromIntegral = (fromIntegral :: Word -> Word32) . naturalToWord
-"fromIntegral/Natural->Int8"
- fromIntegral = (fromIntegral :: Int -> Int8) . naturalToInt
-"fromIntegral/Natural->Int16"
- fromIntegral = (fromIntegral :: Int -> Int16) . naturalToInt
-"fromIntegral/Natural->Int32"
- fromIntegral = (fromIntegral :: Int -> Int32) . naturalToInt
- #-}
-
-{-# RULES
-"fromIntegral/Word->Natural" fromIntegral = wordToNatural
-"fromIntegral/Word8->Natural"
- fromIntegral = wordToNatural . (fromIntegral :: Word8 -> Word)
-"fromIntegral/Word16->Natural"
- fromIntegral = wordToNatural . (fromIntegral :: Word16 -> Word)
-"fromIntegral/Word32->Natural"
- fromIntegral = wordToNatural . (fromIntegral :: Word32 -> Word)
-"fromIntegral/Int->Natural" fromIntegral = intToNatural
-"fromIntegral/Int8->Natural"
- fromIntegral = intToNatural . (fromIntegral :: Int8 -> Int)
-"fromIntegral/Int16->Natural"
- fromIntegral = intToNatural . (fromIntegral :: Int16 -> Int)
-"fromIntegral/Int32->Natural"
- fromIntegral = intToNatural . (fromIntegral :: Int32 -> Int)
- #-}
-
-#if WORD_SIZE_IN_BITS == 64
--- these RULES are valid for Word==Word64 & Int==Int64
-{-# RULES
-"fromIntegral/Natural->Word64"
- fromIntegral = (fromIntegral :: Word -> Word64) . naturalToWord
-"fromIntegral/Natural->Int64"
- fromIntegral = (fromIntegral :: Int -> Int64) . naturalToInt
-"fromIntegral/Word64->Natural"
- fromIntegral = wordToNatural . (fromIntegral :: Word64 -> Word)
-"fromIntegral/Int64->Natural"
- fromIntegral = intToNatural . (fromIntegral :: Int64 -> Int)
- #-}
-#endif
-
--- | @since 4.8.0.0
-instance Show Natural where
- showsPrec p (NatS# w#) = showsPrec p (W# w#)
- showsPrec p (NatJ# bn) = showsPrec p (Jp# bn)
-
--- | @since 4.8.0.0
-instance Read Natural where
- readsPrec d = map (\(n, s) -> (fromInteger n, s))
- . filter ((>= 0) . (\(x,_)->x)) . readsPrec d
-
--- | @since 4.8.0.0
-instance Num Natural where
- fromInteger = naturalFromInteger
+ && isTrue# (sizeofBigNat# bn ># 0#)
- (+) = plusNatural
- (*) = timesNatural
- (-) = minusNatural
+signumNatural :: Natural -> Natural
+signumNatural (NatS# 0##) = NatS# 0##
+signumNatural _ = NatS# 1##
+{-# CONSTANT_FOLDED signumNatural #-}
- abs = id
-
- signum (NatS# 0##) = NatS# 0##
- signum _ = NatS# 1##
-
- negate (NatS# 0##) = NatS# 0##
- negate _ = underflowError
+negateNatural :: Natural -> Natural
+negateNatural (NatS# 0##) = NatS# 0##
+negateNatural _ = underflowError
+{-# CONSTANT_FOLDED negateNatural #-}
-- | @since 4.10.0.0
naturalFromInteger :: Integer -> Natural
-naturalFromInteger (S# i#) | I# i# >= 0 = NatS# (int2Word# i#)
-naturalFromInteger (Jp# bn) = bigNatToNatural bn
-naturalFromInteger _ = underflowError
-{-# INLINE naturalFromInteger #-}
-
--- | @since 4.8.0.0
-instance Real Natural where
- toRational (NatS# w) = toRational (W# w)
- toRational (NatJ# bn) = toRational (Jp# bn)
-
-#if OPTIMISE_INTEGER_GCD_LCM
-{-# RULES
-"gcd/Natural->Natural->Natural" gcd = gcdNatural
-"lcm/Natural->Natural->Natural" lcm = lcmNatural
- #-}
+naturalFromInteger (S# i#)
+ | isTrue# (i# >=# 0#) = NatS# (int2Word# i#)
+naturalFromInteger (Jp# bn) = bigNatToNatural bn
+naturalFromInteger _ = underflowError
+{-# CONSTANT_FOLDED naturalFromInteger #-}
-- | Compute greatest common divisor.
gcdNatural :: Natural -> Natural -> Natural
gcdNatural (NatS# 0##) y = y
gcdNatural x (NatS# 0##) = x
-gcdNatural (NatS# 1##) _ = (NatS# 1##)
-gcdNatural _ (NatS# 1##) = (NatS# 1##)
+gcdNatural (NatS# 1##) _ = NatS# 1##
+gcdNatural _ (NatS# 1##) = NatS# 1##
gcdNatural (NatJ# x) (NatJ# y) = bigNatToNatural (gcdBigNat x y)
gcdNatural (NatJ# x) (NatS# y) = NatS# (gcdBigNatWord x y)
gcdNatural (NatS# x) (NatJ# y) = NatS# (gcdBigNatWord y x)
@@ -222,149 +189,107 @@ gcdNatural (NatS# x) (NatS# y) = NatS# (gcdWord x y)
-- | compute least common multiplier.
lcmNatural :: Natural -> Natural -> Natural
-lcmNatural (NatS# 0##) _ = (NatS# 0##)
-lcmNatural _ (NatS# 0##) = (NatS# 0##)
+lcmNatural (NatS# 0##) _ = NatS# 0##
+lcmNatural _ (NatS# 0##) = NatS# 0##
lcmNatural (NatS# 1##) y = y
lcmNatural x (NatS# 1##) = x
-lcmNatural x y = (x `quot` (gcdNatural x y)) * y
-
-#endif
-
--- | @since 4.8.0.0
-instance Enum Natural where
- succ n = n `plusNatural` NatS# 1##
- pred n = n `minusNatural` NatS# 1##
-
- toEnum = intToNatural
-
- fromEnum (NatS# w) | i >= 0 = i
- where
- i = fromIntegral (W# w)
- fromEnum _ = errorWithoutStackTrace "fromEnum: out of Int range"
-
- enumFrom x = enumDeltaNatural x (NatS# 1##)
- enumFromThen x y
- | x <= y = enumDeltaNatural x (y-x)
- | otherwise = enumNegDeltaToNatural x (x-y) (NatS# 0##)
-
- enumFromTo x lim = enumDeltaToNatural x (NatS# 1##) lim
- enumFromThenTo x y lim
- | x <= y = enumDeltaToNatural x (y-x) lim
- | otherwise = enumNegDeltaToNatural x (x-y) lim
-
-----------------------------------------------------------------------------
--- Helpers for 'Enum Natural'; TODO: optimise & make fusion work
-
-enumDeltaNatural :: Natural -> Natural -> [Natural]
-enumDeltaNatural !x d = x : enumDeltaNatural (x+d) d
-
-enumDeltaToNatural :: Natural -> Natural -> Natural -> [Natural]
-enumDeltaToNatural x0 delta lim = go x0
- where
- go x | x > lim = []
- | otherwise = x : go (x+delta)
-
-enumNegDeltaToNatural :: Natural -> Natural -> Natural -> [Natural]
-enumNegDeltaToNatural x0 ndelta lim = go x0
- where
- go x | x < lim = []
- | x >= ndelta = x : go (x-ndelta)
- | otherwise = [x]
+lcmNatural x y = (x `quotNatural` (gcdNatural x y)) `timesNatural` y
----------------------------------------------------------------------------
--- | @since 4.8.0.0
-instance Integral Natural where
- toInteger (NatS# w) = wordToInteger w
- toInteger (NatJ# bn) = Jp# bn
-
- divMod = quotRem
- div = quot
- mod = rem
-
- quotRem _ (NatS# 0##) = divZeroError
- quotRem n (NatS# 1##) = (n,NatS# 0##)
- quotRem n@(NatS# _) (NatJ# _) = (NatS# 0##, n)
- quotRem (NatS# n) (NatS# d) = case quotRem (W# n) (W# d) of
- (q,r) -> (wordToNatural q, wordToNatural r)
- quotRem (NatJ# n) (NatS# d) = case quotRemBigNatWord n d of
- (# q,r #) -> (bigNatToNatural q, NatS# r)
- quotRem (NatJ# n) (NatJ# d) = case quotRemBigNat n d of
- (# q,r #) -> (bigNatToNatural q, bigNatToNatural r)
-
- quot _ (NatS# 0##) = divZeroError
- quot n (NatS# 1##) = n
- quot (NatS# _) (NatJ# _) = NatS# 0##
- quot (NatS# n) (NatS# d) = wordToNatural (quot (W# n) (W# d))
- quot (NatJ# n) (NatS# d) = bigNatToNatural (quotBigNatWord n d)
- quot (NatJ# n) (NatJ# d) = bigNatToNatural (quotBigNat n d)
-
- rem _ (NatS# 0##) = divZeroError
- rem _ (NatS# 1##) = NatS# 0##
- rem n@(NatS# _) (NatJ# _) = n
- rem (NatS# n) (NatS# d) = wordToNatural (rem (W# n) (W# d))
- rem (NatJ# n) (NatS# d) = NatS# (remBigNatWord n d)
- rem (NatJ# n) (NatJ# d) = bigNatToNatural (remBigNat n d)
-
--- | @since 4.8.0.0
-instance Ix Natural where
- range (m,n) = [m..n]
- inRange (m,n) i = m <= i && i <= n
- unsafeIndex (m,_) i = fromIntegral (i-m)
- index b i | inRange b i = unsafeIndex b i
- | otherwise = indexError b i "Natural"
-
-
--- | @since 4.8.0.0
-instance Bits Natural where
- NatS# n .&. NatS# m = wordToNatural (W# n .&. W# m)
- NatS# n .&. NatJ# m = wordToNatural (W# n .&. W# (bigNatToWord m))
- NatJ# n .&. NatS# m = wordToNatural (W# (bigNatToWord n) .&. W# m)
- NatJ# n .&. NatJ# m = bigNatToNatural (andBigNat n m)
-
- NatS# n .|. NatS# m = wordToNatural (W# n .|. W# m)
- NatS# n .|. NatJ# m = NatJ# (orBigNat (wordToBigNat n) m)
- NatJ# n .|. NatS# m = NatJ# (orBigNat n (wordToBigNat m))
- NatJ# n .|. NatJ# m = NatJ# (orBigNat n m)
-
- NatS# n `xor` NatS# m = wordToNatural (W# n `xor` W# m)
- NatS# n `xor` NatJ# m = NatJ# (xorBigNat (wordToBigNat n) m)
- NatJ# n `xor` NatS# m = NatJ# (xorBigNat n (wordToBigNat m))
- NatJ# n `xor` NatJ# m = bigNatToNatural (xorBigNat n m)
-
- complement _ = errorWithoutStackTrace "Bits.complement: Natural complement undefined"
-
- bitSizeMaybe _ = Nothing
- bitSize = errorWithoutStackTrace "Natural: bitSize"
- isSigned _ = False
-
- bit i@(I# i#) | i < finiteBitSize (0::Word) = wordToNatural (bit i)
- | otherwise = NatJ# (bitBigNat i#)
-
- testBit (NatS# w) i = testBit (W# w) i
- testBit (NatJ# bn) (I# i#) = testBitBigNat bn i#
-
- -- TODO: setBit, clearBit, complementBit (needs more primitives)
-
- shiftL n 0 = n
- shiftL (NatS# 0##) _ = NatS# 0##
- shiftL (NatS# 1##) i = bit i
- shiftL (NatS# w) (I# i#)
- = bigNatToNatural $ shiftLBigNat (wordToBigNat w) i#
- shiftL (NatJ# bn) (I# i#)
- = bigNatToNatural $ shiftLBigNat bn i#
-
- shiftR n 0 = n
- shiftR (NatS# w) i = wordToNatural $ shiftR (W# w) i
- shiftR (NatJ# bn) (I# i#) = bigNatToNatural (shiftRBigNat bn i#)
-
- rotateL = shiftL
- rotateR = shiftR
-
- popCount (NatS# w) = popCount (W# w)
- popCount (NatJ# bn) = I# (popCountBigNat bn)
-
- zeroBits = NatS# 0##
+quotRemNatural :: Natural -> Natural -> (Natural, Natural)
+quotRemNatural _ (NatS# 0##) = divZeroError
+quotRemNatural n (NatS# 1##) = (n,NatS# 0##)
+quotRemNatural n@(NatS# _) (NatJ# _) = (NatS# 0##, n)
+quotRemNatural (NatS# n) (NatS# d) = case quotRemWord# n d of
+ (# q, r #) -> (NatS# q, NatS# r)
+quotRemNatural (NatJ# n) (NatS# d) = case quotRemBigNatWord n d of
+ (# q, r #) -> (bigNatToNatural q, NatS# r)
+quotRemNatural (NatJ# n) (NatJ# d) = case quotRemBigNat n d of
+ (# q, r #) -> (bigNatToNatural q, bigNatToNatural r)
+{-# CONSTANT_FOLDED quotRemNatural #-}
+
+quotNatural :: Natural -> Natural -> Natural
+quotNatural _ (NatS# 0##) = divZeroError
+quotNatural n (NatS# 1##) = n
+quotNatural (NatS# _) (NatJ# _) = NatS# 0##
+quotNatural (NatS# n) (NatS# d) = NatS# (quotWord# n d)
+quotNatural (NatJ# n) (NatS# d) = bigNatToNatural (quotBigNatWord n d)
+quotNatural (NatJ# n) (NatJ# d) = bigNatToNatural (quotBigNat n d)
+{-# CONSTANT_FOLDED quotNatural #-}
+
+remNatural :: Natural -> Natural -> Natural
+remNatural _ (NatS# 0##) = divZeroError
+remNatural _ (NatS# 1##) = NatS# 0##
+remNatural n@(NatS# _) (NatJ# _) = n
+remNatural (NatS# n) (NatS# d) = NatS# (remWord# n d)
+remNatural (NatJ# n) (NatS# d) = NatS# (remBigNatWord n d)
+remNatural (NatJ# n) (NatJ# d) = bigNatToNatural (remBigNat n d)
+{-# CONSTANT_FOLDED remNatural #-}
+
+-- | @since 4.X.0.0
+naturalToInteger :: Natural -> Integer
+naturalToInteger (NatS# w) = wordToInteger w
+naturalToInteger (NatJ# bn) = Jp# bn
+{-# CONSTANT_FOLDED naturalToInteger #-}
+
+andNatural :: Natural -> Natural -> Natural
+andNatural (NatS# n) (NatS# m) = NatS# (n `and#` m)
+andNatural (NatS# n) (NatJ# m) = NatS# (n `and#` bigNatToWord m)
+andNatural (NatJ# n) (NatS# m) = NatS# (bigNatToWord n `and#` m)
+andNatural (NatJ# n) (NatJ# m) = bigNatToNatural (andBigNat n m)
+{-# CONSTANT_FOLDED andNatural #-}
+
+orNatural :: Natural -> Natural -> Natural
+orNatural (NatS# n) (NatS# m) = NatS# (n `or#` m)
+orNatural (NatS# n) (NatJ# m) = NatJ# (orBigNat (wordToBigNat n) m)
+orNatural (NatJ# n) (NatS# m) = NatJ# (orBigNat n (wordToBigNat m))
+orNatural (NatJ# n) (NatJ# m) = NatJ# (orBigNat n m)
+{-# CONSTANT_FOLDED orNatural #-}
+
+xorNatural :: Natural -> Natural -> Natural
+xorNatural (NatS# n) (NatS# m) = NatS# (n `xor#` m)
+xorNatural (NatS# n) (NatJ# m) = NatJ# (xorBigNat (wordToBigNat n) m)
+xorNatural (NatJ# n) (NatS# m) = NatJ# (xorBigNat n (wordToBigNat m))
+xorNatural (NatJ# n) (NatJ# m) = bigNatToNatural (xorBigNat n m)
+{-# CONSTANT_FOLDED xorNatural #-}
+
+bitNatural :: Int# -> Natural
+bitNatural i#
+ | isTrue# (i# <# WORD_SIZE_IN_BITS#) = NatS# (1## `uncheckedShiftL#` i#)
+ | True = NatJ# (bitBigNat i#)
+{-# CONSTANT_FOLDED bitNatural #-}
+
+testBitNatural :: Natural -> Int -> Bool
+testBitNatural (NatS# w) (I# i#)
+ | isTrue# (i# <# WORD_SIZE_IN_BITS#) =
+ isTrue# ((w `and#` (1## `uncheckedShiftL#` i#)) `neWord#` 0##)
+ | True = False
+testBitNatural (NatJ# bn) (I# i#) = testBitBigNat bn i#
+{-# CONSTANT_FOLDED testBitNatural #-}
+
+popCountNatural :: Natural -> Int
+popCountNatural (NatS# w) = I# (word2Int# (popCnt# w))
+popCountNatural (NatJ# bn) = I# (popCountBigNat bn)
+{-# CONSTANT_FOLDED popCountNatural #-}
+
+shiftLNatural :: Natural -> Int -> Natural
+shiftLNatural n (I# 0#) = n
+shiftLNatural (NatS# 0##) _ = NatS# 0##
+shiftLNatural (NatS# 1##) (I# i#) = bitNatural i#
+shiftLNatural (NatS# w) (I# i#)
+ = bigNatToNatural (shiftLBigNat (wordToBigNat w) i#)
+shiftLNatural (NatJ# bn) (I# i#)
+ = bigNatToNatural (shiftLBigNat bn i#)
+{-# CONSTANT_FOLDED shiftLNatural #-}
+
+shiftRNatural :: Natural -> Int -> Natural
+shiftRNatural n (I# 0#) = n
+shiftRNatural (NatS# w) (I# i#)
+ | isTrue# (i# >=# WORD_SIZE_IN_BITS#) = NatS# 0##
+ | True = NatS# (w `uncheckedShiftRL#` i#)
+shiftRNatural (NatJ# bn) (I# i#) = bigNatToNatural (shiftRBigNat bn i#)
+{-# CONSTANT_FOLDED shiftRNatural #-}
----------------------------------------------------------------------------
@@ -379,6 +304,7 @@ plusNatural (NatS# x) (NatS# y)
plusNatural (NatS# x) (NatJ# y) = NatJ# (plusBigNatWord y x)
plusNatural (NatJ# x) (NatS# y) = NatJ# (plusBigNatWord x y)
plusNatural (NatJ# x) (NatJ# y) = NatJ# (plusBigNat x y)
+{-# CONSTANT_FOLDED plusNatural #-}
-- | 'Natural' multiplication
timesNatural :: Natural -> Natural -> Natural
@@ -389,12 +315,14 @@ timesNatural (NatS# 1##) y = y
timesNatural (NatS# x) (NatS# y) = case timesWord2# x y of
(# 0##, 0## #) -> NatS# 0##
(# 0##, xy #) -> NatS# xy
- (# h , l #) -> NatJ# $ wordToBigNat2 h l
-timesNatural (NatS# x) (NatJ# y) = NatJ# $ timesBigNatWord y x
-timesNatural (NatJ# x) (NatS# y) = NatJ# $ timesBigNatWord x y
-timesNatural (NatJ# x) (NatJ# y) = NatJ# $ timesBigNat x y
-
--- | 'Natural' subtraction. May @'throw' 'Underflow'@.
+ (# h , l #) -> NatJ# (wordToBigNat2 h l)
+timesNatural (NatS# x) (NatJ# y) = NatJ# (timesBigNatWord y x)
+timesNatural (NatJ# x) (NatS# y) = NatJ# (timesBigNatWord x y)
+timesNatural (NatJ# x) (NatJ# y) = NatJ# (timesBigNat x y)
+{-# CONSTANT_FOLDED timesNatural #-}
+
+-- | 'Natural' subtraction. May @'Control.Exception.throw'
+-- 'Control.Exception.Underflow'@.
minusNatural :: Natural -> Natural -> Natural
minusNatural x (NatS# 0##) = x
minusNatural (NatS# x) (NatS# y) = case subWordC# x y of
@@ -402,9 +330,10 @@ minusNatural (NatS# x) (NatS# y) = case subWordC# x y of
_ -> underflowError
minusNatural (NatS# _) (NatJ# _) = underflowError
minusNatural (NatJ# x) (NatS# y)
- = bigNatToNatural $ minusBigNatWord x y
+ = bigNatToNatural (minusBigNatWord x y)
minusNatural (NatJ# x) (NatJ# y)
- = bigNatToNatural $ minusBigNat x y
+ = bigNatToNatural (minusBigNat x y)
+{-# CONSTANT_FOLDED minusNatural #-}
-- | 'Natural' subtraction. Returns 'Nothing's for non-positive results.
--
@@ -414,34 +343,27 @@ minusNaturalMaybe x (NatS# 0##) = Just x
minusNaturalMaybe (NatS# x) (NatS# y) = case subWordC# x y of
(# l, 0# #) -> Just (NatS# l)
_ -> Nothing
- where
minusNaturalMaybe (NatS# _) (NatJ# _) = Nothing
minusNaturalMaybe (NatJ# x) (NatS# y)
- = Just $ bigNatToNatural $ minusBigNatWord x y
+ = Just (bigNatToNatural (minusBigNatWord x y))
minusNaturalMaybe (NatJ# x) (NatJ# y)
| isTrue# (isNullBigNat# res) = Nothing
- | otherwise = Just (bigNatToNatural res)
+ | True = Just (bigNatToNatural res)
where
res = minusBigNat x y
-- | Convert 'BigNat' to 'Natural'.
--- Throws 'Underflow' if passed a 'nullBigNat'.
+-- Throws 'Control.Exception.Underflow' if passed a 'nullBigNat'.
bigNatToNatural :: BigNat -> Natural
bigNatToNatural bn
| isTrue# (sizeofBigNat# bn ==# 1#) = NatS# (bigNatToWord bn)
| isTrue# (isNullBigNat# bn) = underflowError
- | otherwise = NatJ# bn
+ | True = NatJ# bn
naturalToBigNat :: Natural -> BigNat
naturalToBigNat (NatS# w#) = wordToBigNat w#
naturalToBigNat (NatJ# bn) = bn
--- | Convert 'Int' to 'Natural'.
--- Throws 'Underflow' when passed a negative 'Int'.
-intToNatural :: Int -> Natural
-intToNatural i | i<0 = underflowError
-intToNatural (I# i#) = NatS# (int2Word# i#)
-
naturalToWord :: Natural -> Word
naturalToWord (NatS# w#) = W# w#
naturalToWord (NatJ# bn) = W# (bigNatToWord bn)
@@ -450,182 +372,184 @@ naturalToInt :: Natural -> Int
naturalToInt (NatS# w#) = I# (word2Int# w#)
naturalToInt (NatJ# bn) = I# (bigNatToInt bn)
-#else /* !HAVE_GMP_BIGNAT */
+----------------------------------------------------------------------------
+
+-- | Convert a Word# into a Natural
+--
+-- Built-in rule ensures that applications of this function to literal Word# are
+-- lifted into Natural literals.
+wordToNatural# :: Word# -> Natural
+wordToNatural# w# = NatS# w#
+{-# CONSTANT_FOLDED wordToNatural# #-}
+
+-- | Convert a Word# into a Natural
+--
+-- In base we can't use wordToNatural# as built-in rules transform some of them
+-- into Natural literals. Use this function instead.
+wordToNaturalBase :: Word# -> Natural
+wordToNaturalBase w# = NatS# w#
+
+#else /* !defined(MIN_VERSION_integer_gmp) */
----------------------------------------------------------------------------
-- Use wrapped 'Integer' as fallback; taken from Edward Kmett's nats package
-- | Type representing arbitrary-precision non-negative integers.
--
--- Operations whose result would be negative
--- @'throw' ('Underflow' :: 'ArithException')@.
+-- Operations whose result would be negative @'Control.Exception.throw'
+-- ('Control.Exception.Underflow' :: 'Control.Exception.ArithException')@.
--
-- @since 4.8.0.0
newtype Natural = Natural Integer -- ^ __Invariant__: non-negative 'Integer'
- deriving (Eq,Ord,Ix)
+ deriving (Eq,Ord)
+
-- | Test whether all internal invariants are satisfied by 'Natural' value
--
-- This operation is mostly useful for test-suites and/or code which
--- constructs 'Integer' values directly.
+-- constructs 'Natural' values directly.
--
-- @since 4.8.0.0
isValidNatural :: Natural -> Bool
-isValidNatural (Natural i) = i >= 0
-
--- | @since 4.8.0.0
-instance Read Natural where
- readsPrec d = map (\(n, s) -> (Natural n, s))
- . filter ((>= 0) . (\(x,_)->x)) . readsPrec d
-
--- | @since 4.8.0.0
-instance Show Natural where
- showsPrec d (Natural i) = showsPrec d i
-
--- | @since 4.8.0.0
-instance Num Natural where
- Natural n + Natural m = Natural (n + m)
- {-# INLINE (+) #-}
- Natural n * Natural m = Natural (n * m)
- {-# INLINE (*) #-}
- Natural n - Natural m | result < 0 = underflowError
- | otherwise = Natural result
- where result = n - m
- {-# INLINE (-) #-}
- abs (Natural n) = Natural n
- {-# INLINE abs #-}
- signum (Natural n) = Natural (signum n)
- {-# INLINE signum #-}
- fromInteger = naturalFromInteger
- {-# INLINE fromInteger #-}
+isValidNatural (Natural i) = i >= wordToInteger 0##
+
+-- | Convert a 'Word#' into a 'Natural'
+--
+-- Built-in rule ensures that applications of this function to literal 'Word#'
+-- are lifted into 'Natural' literals.
+wordToNatural# :: Word# -> Natural
+wordToNatural# w## = Natural (wordToInteger w##)
+{-# CONSTANT_FOLDED wordToNatural# #-}
+
+-- | Convert a 'Word#' into a Natural
+--
+-- In base we can't use wordToNatural# as built-in rules transform some of them
+-- into Natural literals. Use this function instead.
+wordToNaturalBase :: Word# -> Natural
+wordToNaturalBase w## = Natural (wordToInteger w##)
-- | @since 4.10.0.0
naturalFromInteger :: Integer -> Natural
naturalFromInteger n
- | n >= 0 = Natural n
- | otherwise = underflowError
+ | n >= wordToInteger 0## = Natural n
+ | True = underflowError
{-# INLINE naturalFromInteger #-}
-- | 'Natural' subtraction. Returns 'Nothing's for non-positive results.
--
-- @since 4.8.0.0
minusNaturalMaybe :: Natural -> Natural -> Maybe Natural
-minusNaturalMaybe x y
- | x >= y = Just (x - y)
- | otherwise = Nothing
-
--- | @since 4.8.0.0
-instance Bits Natural where
- Natural n .&. Natural m = Natural (n .&. m)
- {-# INLINE (.&.) #-}
- Natural n .|. Natural m = Natural (n .|. m)
- {-# INLINE (.|.) #-}
- xor (Natural n) (Natural m) = Natural (xor n m)
- {-# INLINE xor #-}
- complement _ = errorWithoutStackTrace "Bits.complement: Natural complement undefined"
- {-# INLINE complement #-}
- shift (Natural n) = Natural . shift n
- {-# INLINE shift #-}
- rotate (Natural n) = Natural . rotate n
- {-# INLINE rotate #-}
- bit = Natural . bit
- {-# INLINE bit #-}
- setBit (Natural n) = Natural . setBit n
- {-# INLINE setBit #-}
- clearBit (Natural n) = Natural . clearBit n
- {-# INLINE clearBit #-}
- complementBit (Natural n) = Natural . complementBit n
- {-# INLINE complementBit #-}
- testBit (Natural n) = testBit n
- {-# INLINE testBit #-}
- bitSizeMaybe _ = Nothing
- {-# INLINE bitSizeMaybe #-}
- bitSize = errorWithoutStackTrace "Natural: bitSize"
- {-# INLINE bitSize #-}
- isSigned _ = False
- {-# INLINE isSigned #-}
- shiftL (Natural n) = Natural . shiftL n
- {-# INLINE shiftL #-}
- shiftR (Natural n) = Natural . shiftR n
- {-# INLINE shiftR #-}
- rotateL (Natural n) = Natural . rotateL n
- {-# INLINE rotateL #-}
- rotateR (Natural n) = Natural . rotateR n
- {-# INLINE rotateR #-}
- popCount (Natural n) = popCount n
- {-# INLINE popCount #-}
- zeroBits = Natural 0
-
--- | @since 4.8.0.0
-instance Real Natural where
- toRational (Natural a) = toRational a
- {-# INLINE toRational #-}
-
--- | @since 4.8.0.0
-instance Enum Natural where
- pred (Natural 0) = errorWithoutStackTrace "Natural.pred: 0"
- pred (Natural n) = Natural (pred n)
- {-# INLINE pred #-}
- succ (Natural n) = Natural (succ n)
- {-# INLINE succ #-}
- fromEnum (Natural n) = fromEnum n
- {-# INLINE fromEnum #-}
- toEnum n | n < 0 = errorWithoutStackTrace "Natural.toEnum: negative"
- | otherwise = Natural (toEnum n)
- {-# INLINE toEnum #-}
-
- enumFrom = coerce (enumFrom :: Integer -> [Integer])
- enumFromThen x y
- | x <= y = coerce (enumFromThen :: Integer -> Integer -> [Integer]) x y
- | otherwise = enumFromThenTo x y 0
-
- enumFromTo = coerce (enumFromTo :: Integer -> Integer -> [Integer])
- enumFromThenTo
- = coerce (enumFromThenTo :: Integer -> Integer -> Integer -> [Integer])
-
--- | @since 4.8.0.0
-instance Integral Natural where
- quot (Natural a) (Natural b) = Natural (quot a b)
- {-# INLINE quot #-}
- rem (Natural a) (Natural b) = Natural (rem a b)
- {-# INLINE rem #-}
- div (Natural a) (Natural b) = Natural (div a b)
- {-# INLINE div #-}
- mod (Natural a) (Natural b) = Natural (mod a b)
- {-# INLINE mod #-}
- divMod (Natural a) (Natural b) = (Natural q, Natural r)
- where (q,r) = divMod a b
- {-# INLINE divMod #-}
- quotRem (Natural a) (Natural b) = (Natural q, Natural r)
- where (q,r) = quotRem a b
- {-# INLINE quotRem #-}
- toInteger (Natural a) = a
- {-# INLINE toInteger #-}
+minusNaturalMaybe (Natural x) (Natural y)
+ | x >= y = Just (Natural (x `minusInteger` y))
+ | True = Nothing
+
+shiftLNatural :: Natural -> Int -> Natural
+shiftLNatural (Natural n) (I# i) = Natural (n `shiftLInteger` i)
+{-# CONSTANT_FOLDED shiftLNatural #-}
+
+shiftRNatural :: Natural -> Int -> Natural
+shiftRNatural (Natural n) (I# i) = Natural (n `shiftRInteger` i)
+{-# CONSTANT_FOLDED shiftRNatural #-}
+
+plusNatural :: Natural -> Natural -> Natural
+plusNatural (Natural x) (Natural y) = Natural (x `plusInteger` y)
+{-# CONSTANT_FOLDED plusNatural #-}
+
+minusNatural :: Natural -> Natural -> Natural
+minusNatural (Natural x) (Natural y) = Natural (x `minusInteger` y)
+{-# CONSTANT_FOLDED minusNatural #-}
+
+timesNatural :: Natural -> Natural -> Natural
+timesNatural (Natural x) (Natural y) = Natural (x `timesInteger` y)
+{-# CONSTANT_FOLDED timesNatural #-}
+
+orNatural :: Natural -> Natural -> Natural
+orNatural (Natural x) (Natural y) = Natural (x `orInteger` y)
+{-# CONSTANT_FOLDED orNatural #-}
+
+xorNatural :: Natural -> Natural -> Natural
+xorNatural (Natural x) (Natural y) = Natural (x `xorInteger` y)
+{-# CONSTANT_FOLDED xorNatural #-}
+
+andNatural :: Natural -> Natural -> Natural
+andNatural (Natural x) (Natural y) = Natural (x `andInteger` y)
+{-# CONSTANT_FOLDED andNatural #-}
+
+naturalToInt :: Natural -> Int
+naturalToInt (Natural i) = I# (integerToInt i)
+
+naturalToWord :: Natural -> Word
+naturalToWord (Natural i) = W# (integerToWord i)
+
+naturalToInteger :: Natural -> Integer
+naturalToInteger (Natural i) = i
+{-# CONSTANT_FOLDED naturalToInteger #-}
+
+testBitNatural :: Natural -> Int -> Bool
+testBitNatural (Natural n) (I# i) = testBitInteger n i
+{-# CONSTANT_FOLDED testBitNatural #-}
+
+bitNatural :: Int# -> Natural
+bitNatural i#
+ | isTrue# (i# <# WORD_SIZE_IN_BITS#) = wordToNaturalBase (1## `uncheckedShiftL#` i#)
+ | True = Natural (1 `shiftLInteger` i#)
+{-# CONSTANT_FOLDED bitNatural #-}
+
+quotNatural :: Natural -> Natural -> Natural
+quotNatural n@(Natural x) (Natural y)
+ | y == wordToInteger 0## = divZeroError
+ | y == wordToInteger 1## = n
+ | True = Natural (x `quotInteger` y)
+{-# CONSTANT_FOLDED quotNatural #-}
+
+remNatural :: Natural -> Natural -> Natural
+remNatural (Natural x) (Natural y)
+ | y == wordToInteger 0## = divZeroError
+ | y == wordToInteger 1## = wordToNaturalBase 0##
+ | True = Natural (x `remInteger` y)
+{-# CONSTANT_FOLDED remNatural #-}
+
+quotRemNatural :: Natural -> Natural -> (Natural, Natural)
+quotRemNatural n@(Natural x) (Natural y)
+ | y == wordToInteger 0## = divZeroError
+ | y == wordToInteger 1## = (n,wordToNaturalBase 0##)
+ | True = case quotRemInteger x y of
+ (# k, r #) -> (Natural k, Natural r)
+{-# CONSTANT_FOLDED quotRemNatural #-}
+
+signumNatural :: Natural -> Natural
+signumNatural (Natural x)
+ | x == wordToInteger 0## = wordToNaturalBase 0##
+ | True = wordToNaturalBase 1##
+{-# CONSTANT_FOLDED signumNatural #-}
+
+negateNatural :: Natural -> Natural
+negateNatural (Natural x)
+ | x == wordToInteger 0## = wordToNaturalBase 0##
+ | True = underflowError
+{-# CONSTANT_FOLDED negateNatural #-}
+
#endif
-- | Construct 'Natural' from 'Word' value.
--
-- @since 4.8.0.0
wordToNatural :: Word -> Natural
-#if HAVE_GMP_BIGNAT
-wordToNatural (W# w#) = NatS# w#
-#else
-wordToNatural w = Natural (fromIntegral w)
-#endif
+wordToNatural (W# w#) = wordToNatural# w#
-- | Try downcasting 'Natural' to 'Word' value.
-- Returns 'Nothing' if value doesn't fit in 'Word'.
--
-- @since 4.8.0.0
naturalToWordMaybe :: Natural -> Maybe Word
-#if HAVE_GMP_BIGNAT
+#if defined(MIN_VERSION_integer_gmp)
naturalToWordMaybe (NatS# w#) = Just (W# w#)
naturalToWordMaybe (NatJ# _) = Nothing
#else
naturalToWordMaybe (Natural i)
- | i <= maxw = Just (fromIntegral i)
- | otherwise = Nothing
+ | i < maxw = Just (W# (integerToWord i))
+ | True = Nothing
where
- maxw = toInteger (maxBound :: Word)
+ maxw = 1 `shiftLInteger` WORD_SIZE_IN_BITS#
#endif
-- | \"@'powModNatural' /b/ /e/ /m/@\" computes base @/b/@ raised to
@@ -633,7 +557,7 @@ naturalToWordMaybe (Natural i)
--
-- @since 4.8.0.0
powModNatural :: Natural -> Natural -> Natural -> Natural
-#if HAVE_GMP_BIGNAT
+#if defined(MIN_VERSION_integer_gmp)
powModNatural _ _ (NatS# 0##) = divZeroError
powModNatural _ _ (NatS# 1##) = NatS# 0##
powModNatural _ (NatS# 0##) _ = NatS# 1##
@@ -646,18 +570,38 @@ powModNatural b e (NatJ# m)
= bigNatToNatural (powModBigNat (naturalToBigNat b) (naturalToBigNat e) m)
#else
-- Portable reference fallback implementation
-powModNatural _ _ 0 = divZeroError
-powModNatural _ _ 1 = 0
-powModNatural _ 0 _ = 1
-powModNatural 0 _ _ = 0
-powModNatural 1 _ _ = 1
-powModNatural b0 e0 m = go b0 e0 1
+powModNatural (Natural b0) (Natural e0) (Natural m)
+ | m == wordToInteger 0## = divZeroError
+ | m == wordToInteger 1## = wordToNaturalBase 0##
+ | e0 == wordToInteger 0## = wordToNaturalBase 1##
+ | b0 == wordToInteger 0## = wordToNaturalBase 0##
+ | b0 == wordToInteger 1## = wordToNaturalBase 1##
+ | True = go b0 e0 (wordToInteger 1##)
where
go !b e !r
- | odd e = go b' e' (r*b `mod` m)
- | e == 0 = r
- | otherwise = go b' e' r
+ | e `testBitInteger` 0# = go b' e' ((r `timesInteger` b) `modInteger` m)
+ | e == wordToInteger 0## = naturalFromInteger r
+ | True = go b' e' r
where
- b' = b*b `mod` m
- e' = e `unsafeShiftR` 1 -- slightly faster than "e `div` 2"
+ b' = (b `timesInteger` b) `modInteger` m
+ e' = e `shiftRInteger` 1# -- slightly faster than "e `div` 2"
#endif
+
+
+-- | Construct 'Natural' value from list of 'Word's.
+--
+-- This function is used by GHC for constructing 'Natural' literals.
+mkNatural :: [Word] -- ^ value expressed in 32 bit chunks, least
+ -- significant first
+ -> Natural
+mkNatural [] = wordToNaturalBase 0##
+mkNatural (W# i : is') = wordToNaturalBase (i `and#` 0xffffffff##) `orNatural`
+ shiftLNatural (mkNatural is') 32
+{-# CONSTANT_FOLDED mkNatural #-}
+
+-- | Convert 'Int' to 'Natural'.
+-- Throws 'Control.Exception.Underflow' when passed a negative 'Int'.
+intToNatural :: Int -> Natural
+intToNatural (I# i#)
+ | isTrue# (i# <# 0#) = underflowError
+ | True = wordToNaturalBase (int2Word# i#)