[commit: ghc] master: Implement `GHC.Natural.powModNatural` (#9818) (859680f)

git at git.haskell.org git at git.haskell.org
Sat Nov 29 17:46:01 UTC 2014


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/859680f6fe952ecbef3395fa4f299530d0f10c58/ghc

>---------------------------------------------------------------

commit 859680f6fe952ecbef3395fa4f299530d0f10c58
Author: Herbert Valerio Riedel <hvr at gnu.org>
Date:   Sat Nov 29 13:02:42 2014 +0100

    Implement `GHC.Natural.powModNatural` (#9818)
    
    This makes use of the `powMod*` primitives provided by
    `integer-gmp-1.0.0`. This is the `Natural`-version of the related
    `GHC.Integer.GMP.Internals.powModInteger` operation.
    
    The fallback implementation uses a square and multiply algorithm,
    compared to which the optimized GMP-based implementation needs much less
    allocations due to in-place mutation during the computation.


>---------------------------------------------------------------

859680f6fe952ecbef3395fa4f299530d0f10c58
 libraries/base/GHC/Natural.hs | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/libraries/base/GHC/Natural.hs b/libraries/base/GHC/Natural.hs
index 221bc31..3519bcf 100644
--- a/libraries/base/GHC/Natural.hs
+++ b/libraries/base/GHC/Natural.hs
@@ -41,6 +41,8 @@ module GHC.Natural
     , naturalToWordMaybe
       -- * Checked subtraction
     , minusNaturalMaybe
+      -- * Modular arithmetic
+    , powModNatural
     ) where
 
 #include "MachDeps.h"
@@ -410,6 +412,10 @@ bigNatToNatural bn
   | isTrue# (isNullBigNat# bn)        = throw Underflow
   | otherwise                         = 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
@@ -602,3 +608,37 @@ instance Data Natural where
                     _ -> error $ "Data.Data.gunfold: Constructor " ++ show c
                                  ++ " is not of type Natural"
   dataTypeOf _ = naturalType
+
+-- | \"@'powModNatural' /b/ /e/ /m/@\" computes base @/b/@ raised to
+-- exponent @/e/@ modulo @/m/@.
+--
+-- /Since: 4.8.0.0/
+powModNatural :: Natural -> Natural -> Natural -> Natural
+#if HAVE_GMP_BIGNAT
+powModNatural _           _           (NatS# 0##) = throw DivideByZero
+powModNatural _           _           (NatS# 1##) = NatS# 0##
+powModNatural _           (NatS# 0##) _           = NatS# 1##
+powModNatural (NatS# 0##) _           _           = NatS# 0##
+powModNatural (NatS# 1##) _           _           = NatS# 1##
+powModNatural (NatS# b)   (NatS# e)   (NatS# m)   = NatS# (powModWord b e m)
+powModNatural b           e           (NatS# m)
+  = NatS# (powModBigNatWord (naturalToBigNat b) (naturalToBigNat e) m)
+powModNatural b           e           (NatJ# m)
+  = bigNatToNatural (powModBigNat (naturalToBigNat b) (naturalToBigNat e) m)
+#else
+-- Portable reference fallback implementation
+powModNatural _ _ 0 = throw DivideByZero
+powModNatural _ _ 1 = 0
+powModNatural _ 0 _ = 1
+powModNatural 0 _ _ = 0
+powModNatural 1 _ _ = 1
+powModNatural b0 e0 m = go b0 e0 1
+  where
+    go !b e !r
+      | odd e     = go b' e' (r*b `mod` m)
+      | e == 0    = r
+      | otherwise = go b' e' r
+      where
+        b' = b*b `mod` m
+        e' = e   `unsafeShiftR` 1 -- slightly faster than "e `div` 2"
+#endif



More information about the ghc-commits mailing list