[Git][ghc/ghc][master] 2 commits: Bignum: implement integerRecipMod (#18427)

Marge Bot gitlab at gitlab.haskell.org
Fri Oct 2 17:52:47 UTC 2020



 Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC


Commits:
12c06927 by Sylvain Henry at 2020-10-02T13:52:38-04:00
Bignum: implement integerRecipMod (#18427)

- - - - -
8dd4f405 by Sylvain Henry at 2020-10-02T13:52:38-04:00
Bignum: implement integerPowMod (#18427)

Incidentally fix powModInteger which was crashing in integer-gmp for
negative exponents when the modular multiplicative inverse for the base
didn't exist. Now we compute it explicitly with integerRecipMod so that
every backend returns the same result without crashing.

- - - - -


17 changed files:

- libraries/ghc-bignum/cbits/gmp_wrappers.c
- libraries/ghc-bignum/src/GHC/Num/Backend/Check.hs
- libraries/ghc-bignum/src/GHC/Num/Backend/FFI.hs
- libraries/ghc-bignum/src/GHC/Num/Backend/GMP.hs
- libraries/ghc-bignum/src/GHC/Num/Backend/Native.hs
- libraries/ghc-bignum/src/GHC/Num/BigNat.hs-boot
- libraries/ghc-bignum/src/GHC/Num/Integer.hs
- libraries/ghc-bignum/src/GHC/Num/Integer.hs-boot
- libraries/ghc-bignum/src/GHC/Num/Natural.hs-boot
- libraries/integer-gmp/src/GHC/Integer/GMP/Internals.hs
- testsuite/tests/lib/integer/all.T
- testsuite/tests/lib/integer/integerGmpInternals.hs
- testsuite/tests/lib/integer/integerGmpInternals.stdout
- testsuite/tests/lib/integer/integerPowMod.hs
- testsuite/tests/lib/integer/integerPowMod.stdout
- + testsuite/tests/lib/integer/integerRecipMod.hs
- + testsuite/tests/lib/integer/integerRecipMod.stdout


Changes:

=====================================
libraries/ghc-bignum/cbits/gmp_wrappers.c
=====================================
@@ -632,8 +632,7 @@ integer_gmp_powm(mp_limb_t rp[], // result
   assert(!mp_limb_zero_p(mp,mn));
 
   if ((mn == 1 || mn == -1) && mp[0] == 1) {
-    rp[0] = 0;
-    return 1;
+    return 0;
   }
 
   if (mp_limb_zero_p(ep,en)) {
@@ -659,11 +658,6 @@ integer_gmp_powm(mp_limb_t rp[], // result
 
   mpz_clear (r);
 
-  if (!rn) {
-    rp[0] = 0;
-    return 1;
-  }
-
   return rn;
 }
 
@@ -720,8 +714,7 @@ integer_gmp_powm_sec(mp_limb_t rp[], // result
   assert(mp[0] & 1);
 
   if ((mn == 1 || mn == -1) && mp[0] == 1) {
-    rp[0] = 0;
-    return 1;
+    return 0;
   }
 
   if (mp_limb_zero_p(ep,en)) {
@@ -753,11 +746,6 @@ integer_gmp_powm_sec(mp_limb_t rp[], // result
 
   mpz_clear (r);
 
-  if (!rn) {
-    rp[0] = 0;
-    return 1;
-  }
-
   return rn;
 }
 
@@ -779,8 +767,7 @@ integer_gmp_invert(mp_limb_t rp[], // result
   if (mp_limb_zero_p(xp,xn)
       || mp_limb_zero_p(mp,mn)
       || ((mn == 1 || mn == -1) && mp[0] == 1)) {
-    rp[0] = 0;
-    return 1;
+    return 0;
   }
 
   const mpz_t x = CONST_MPZ_INIT(xp, xn);
@@ -800,11 +787,6 @@ integer_gmp_invert(mp_limb_t rp[], // result
 
   mpz_clear (r);
 
-  if (!rn) {
-    rp[0] = 0;
-    return 1;
-  }
-
   return rn;
 }
 


=====================================
libraries/ghc-bignum/src/GHC/Num/Backend/Check.hs
=====================================
@@ -17,6 +17,7 @@ import GHC.Types
 import GHC.Num.WordArray
 import GHC.Num.Primitives
 import {-# SOURCE #-} GHC.Num.Integer
+import {-# SOURCE #-} GHC.Num.Natural
 import qualified GHC.Num.Backend.Native   as Native
 import qualified GHC.Num.Backend.Selected as Other
 
@@ -469,3 +470,32 @@ integer_gcde a b =
          then (# g0, x0, y0 #)
          else case unexpectedValue of
             !_ -> (# integerZero, integerZero, integerZero #)
+
+integer_recip_mod
+   :: Integer
+   -> Natural
+   -> (# Natural | () #)
+integer_recip_mod x m =
+   let
+      !r0 = Other.integer_recip_mod x m
+      !r1 = Native.integer_recip_mod x m
+   in case (# r0, r1 #) of
+         (# (# | () #), (# | () #) #) -> r0
+         (# (# y0 | #), (# y1 | #) #)
+            | isTrue# (naturalEq# y0 y1) -> r0
+         _ -> case unexpectedValue of
+            !_ -> (# | () #)
+
+integer_powmod
+   :: Integer
+   -> Natural
+   -> Natural
+   -> Natural
+integer_powmod b e m =
+   let
+      !r0 = Other.integer_powmod b e m
+      !r1 = Native.integer_powmod b e m
+   in if isTrue# (naturalEq# r0 r1)
+         then r0
+         else case unexpectedValue of
+               !_ -> naturalZero


=====================================
libraries/ghc-bignum/src/GHC/Num/Backend/FFI.hs
=====================================
@@ -20,6 +20,8 @@ import GHC.Types
 import GHC.Num.WordArray
 import GHC.Num.Primitives
 import qualified GHC.Num.Backend.Native as Native
+import {-# SOURCE #-} GHC.Num.Natural
+import {-# SOURCE #-} GHC.Num.Integer
 
 default ()
 
@@ -596,3 +598,35 @@ integer_gcde = Native.integer_gcde
    -- for now we use Native's implementation. If some FFI backend user needs a
    -- specific implementation, we'll need to determine a prototype to pass and
    -- return BigNat signs and sizes via FFI.
+
+
+-- | Computes the modular inverse of two non-zero integers.
+--
+-- I.e. y = integer_recip_mod x m
+--        = x^(-1) `mod` m
+--
+-- with 0 < y < abs m
+integer_recip_mod
+   :: Integer
+   -> Natural
+   -> (# Natural | () #)
+integer_recip_mod = Native.integer_recip_mod
+   -- for now we use Native's implementation. If some FFI backend user needs a
+   -- specific implementation, we'll need to determine a prototype to pass and
+   -- return BigNat signs and sizes via FFI.
+
+-- | Computes the modular exponentiation.
+--
+-- I.e. y = integer_powmod b e m
+--        = b^e `mod` m
+--
+-- with 0 <= y < abs m
+integer_powmod
+   :: Integer
+   -> Natural
+   -> Natural
+   -> Natural
+integer_powmod = Native.integer_powmod
+   -- for now we use Native's implementation. If some FFI backend user needs a
+   -- specific implementation, we'll need to determine a prototype to pass and
+   -- return BigNat signs and sizes via FFI.


=====================================
libraries/ghc-bignum/src/GHC/Num/Backend/GMP.hs
=====================================
@@ -28,6 +28,7 @@ import GHC.Types
 import GHC.Magic (runRW#)
 import {-# SOURCE #-} GHC.Num.Integer
 import {-# SOURCE #-} GHC.Num.BigNat
+import {-# SOURCE #-} GHC.Num.Natural
 
 default ()
 
@@ -354,8 +355,37 @@ bignat_powmod
    -> WordArray#
    -> State# RealWorld
    -> State# RealWorld
-bignat_powmod r b e m s =
-   case ioInt# (integer_gmp_powm# r b (wordArraySize# b) e (wordArraySize# e) m (wordArraySize# m)) s of
+bignat_powmod r b e m s = sbignat_powmod r (wordArraySize# b) b e m s
+
+integer_powmod
+   :: Integer
+   -> Natural
+   -> Natural
+   -> Natural
+integer_powmod b e m = naturalFromBigNat# (withNewWordArray# szm io)
+   where
+      !be = naturalToBigNat# e
+      !bm = naturalToBigNat# m
+      !(# sb, bb #) = integerToBigNatSign# b
+      !szb = bigNatSize# bb
+      !szm = bigNatSize# bm
+      !ssb = case sb of -- signed size of b
+               0# -> szb
+               _  -> negateInt# szb
+
+      io r s = sbignat_powmod r ssb bb be bm s
+
+
+sbignat_powmod
+   :: MutableWordArray# RealWorld
+   -> Int#
+   -> WordArray#
+   -> WordArray#
+   -> WordArray#
+   -> State# RealWorld
+   -> State# RealWorld
+sbignat_powmod r b_signed_size b e m s =
+   case ioInt# (integer_gmp_powm# r b b_signed_size e (wordArraySize# e) m (wordArraySize# m)) s of
       (# s', n #) -> mwaSetSize# r (narrowGmpSize# n) s'
 
 integer_gcde
@@ -423,6 +453,32 @@ integer_gcde a b = case runRW# io of (# _, a #) -> a
 
 
 
+integer_recip_mod
+   :: Integer
+   -> Natural
+   -> (# Natural | () #)
+integer_recip_mod x m =
+   let
+      !(#  sign_x, bx #) = integerToBigNatSign# x
+      !bm = naturalToBigNat# m
+      !br = sbignat_recip_mod sign_x bx bm
+   in if isTrue# (bigNatIsZero# br)
+         then (# | () #)
+         else (# naturalFromBigNat# br | #)
+
+
+-- | Return 0 for invalid inputs
+sbignat_recip_mod :: Int# -> BigNat# -> BigNat# -> BigNat#
+sbignat_recip_mod sign_x x m = withNewWordArray# szm io
+  where
+    io r s = case ioInt# (integer_gmp_invert# r x ssx m szm) s of
+               (# s, rn #) -> mwaSetSize# r (narrowGmpSize# rn) s
+    !szx  = bigNatSize# x
+    !szm  = bigNatSize# m
+    !ssx = case sign_x of -- signed size of x
+            0# -> szx
+            _  -> negateInt# szx
+
 ----------------------------------------------------------------------
 -- FFI ccall imports
 
@@ -444,6 +500,11 @@ foreign import ccall unsafe "integer_gmp_gcdext" integer_gmp_gcdext#
   -> ByteArray# -> GmpSize#
   -> IO ()
 
+foreign import ccall unsafe "integer_gmp_invert"
+  integer_gmp_invert# :: MutableByteArray# RealWorld
+                         -> ByteArray# -> GmpSize#
+                         -> ByteArray# -> GmpSize# -> IO GmpSize
+
 -- mp_limb_t mpn_add_1 (mp_limb_t *rp, const mp_limb_t *s1p, mp_size_t n,
 --                      mp_limb_t s2limb)
 foreign import ccall unsafe "gmp.h __gmpn_add_1"


=====================================
libraries/ghc-bignum/src/GHC/Num/Backend/Native.hs
=====================================
@@ -14,7 +14,7 @@ module GHC.Num.Backend.Native where
 #include "MachDeps.h"
 #include "WordSize.h"
 
-#if defined(BIGNUM_NATIVE) || defined(BIGNUM_CHECK)
+#if defined(BIGNUM_NATIVE) || defined(BIGNUM_CHECK) || defined(BIGNUM_FFI)
 import {-# SOURCE #-} GHC.Num.BigNat
 import {-# SOURCE #-} GHC.Num.Natural
 import {-# SOURCE #-} GHC.Num.Integer
@@ -737,3 +737,40 @@ integer_gcde a b = f (# a,integerOne,integerZero #) (# b,integerZero,integerOne
       | True            = case integerQuotRem# old_g g of
                               !(# q, r #) -> f new (# r , old_s `integerSub` (q `integerMul` s)
                                                         , old_t `integerSub` (q `integerMul` t) #)
+
+integer_recip_mod
+   :: Integer
+   -> Natural
+   -> (# Natural | () #)
+integer_recip_mod x m =
+   let m' = integerFromNatural m
+   in case integer_gcde x m' of
+      (# g, a, _b #)
+         -- gcd(x,m) = ax+mb = 1
+         -- ==> ax - 1 = -mb
+         -- ==> ax     = 1 [m]
+         | g `integerEq` integerOne -> (# integerToNatural (a `integerMod` m') | #)
+                                       -- a `mod` m > 0 because m > 0
+         | True                     -> (# | () #)
+
+integer_powmod
+   :: Integer
+   -> Natural
+   -> Natural
+   -> Natural
+integer_powmod b0 e0 m = go b0 e0 integerOne
+   where
+      !m' = integerFromNatural m
+
+      go !b e !r
+        | isTrue# (e `naturalTestBit#` 0##)
+        = go b' e' ((r `integerMul` b) `integerMod` m')
+
+        | naturalIsZero e
+        = integerToNatural r -- r >= 0 by integerMod above
+
+        | True
+        = go b' e' r
+        where
+          b' = (b `integerMul` b) `integerRem` m'
+          e' = e `naturalShiftR#` 1##


=====================================
libraries/ghc-bignum/src/GHC/Num/BigNat.hs-boot
=====================================
@@ -5,11 +5,13 @@
 module GHC.Num.BigNat where
 
 import GHC.Num.WordArray
+import GHC.Num.Primitives
 import GHC.Prim
 
 type BigNat# = WordArray#
 data BigNat = BN# { unBigNat :: BigNat# }
 
+bigNatIsZero# :: BigNat# -> Bool#
 bigNatSize# :: BigNat# -> Int#
 bigNatSubUnsafe :: BigNat# -> BigNat# -> BigNat#
 bigNatMulWord# :: BigNat# -> Word# -> BigNat#


=====================================
libraries/ghc-bignum/src/GHC/Num/Integer.hs
=====================================
@@ -244,6 +244,11 @@ integerIsZero :: Integer -> Bool
 integerIsZero (IS 0#) = True
 integerIsZero _       = False
 
+-- | One predicate
+integerIsOne :: Integer -> Bool
+integerIsOne (IS 1#) = True
+integerIsOne _       = False
+
 -- | Not-equal predicate.
 integerNe :: Integer -> Integer -> Bool
 integerNe !x !y = isTrue# (integerNe# x y)
@@ -1217,3 +1222,50 @@ integerGcde
    -> ( Integer, Integer, Integer)
 integerGcde a b = case integerGcde# a b of
    (# g,x,y #) -> (g,x,y)
+
+
+-- | Computes the modular inverse.
+--
+-- I.e. y = integerRecipMod# x m
+--        = x^(-1) `mod` m
+--
+-- with 0 < y < |m|
+--
+integerRecipMod#
+   :: Integer
+   -> Natural
+   -> (# Natural | () #)
+integerRecipMod# x m
+   | integerIsZero x = (# | () #)
+   | naturalIsZero m = (# | () #)
+   | naturalIsOne  m = (# | () #)
+   | True            = Backend.integer_recip_mod x m
+
+
+-- | Computes the modular exponentiation.
+--
+-- I.e. y = integer_powmod b e m
+--        = b^e `mod` m
+--
+-- with 0 <= y < abs m
+--
+-- If e is negative, we use `integerRecipMod#` to try to find a modular
+-- multiplicative inverse (which may not exist).
+integerPowMod# :: Integer -> Integer -> Natural -> (# Natural | () #)
+integerPowMod# !b !e !m
+   | naturalIsZero m     = (# | () #)
+   | naturalIsOne  m     = (# naturalZero | #)
+   | integerIsZero e     = (# naturalOne  | #)
+   | integerIsZero b     = (# naturalZero | #)
+   | integerIsOne  b     = (# naturalOne  | #)
+     -- when the exponent is negative, try to find the modular multiplicative
+     -- inverse and use it instead
+   | integerIsNegative e = case integerRecipMod# b m of
+      (#    | () #) -> (# | () #)
+      (# b' |    #) -> integerPowMod#
+                        (integerFromNatural b')
+                        (integerNegate e)
+                        m
+
+     -- e > 0 by cases above
+   | True = (# Backend.integer_powmod b (integerToNatural e) m | #)


=====================================
libraries/ghc-bignum/src/GHC/Num/Integer.hs-boot
=====================================
@@ -7,6 +7,7 @@ module GHC.Num.Integer where
 import GHC.Types
 import GHC.Prim
 import {-# SOURCE #-} GHC.Num.BigNat
+import {-# SOURCE #-} GHC.Num.Natural
 
 data Integer
 
@@ -17,14 +18,20 @@ integerEq# :: Integer -> Integer -> Int#
 integerEq :: Integer -> Integer -> Bool
 integerGt :: Integer -> Integer -> Bool
 integerIsZero :: Integer -> Bool
+integerIsOne :: Integer -> Bool
 integerIsNegative :: Integer -> Bool
 
 integerSub :: Integer -> Integer -> Integer
 integerMul :: Integer -> Integer -> Integer
+integerMod :: Integer -> Integer -> Integer
+integerRem :: Integer -> Integer -> Integer
 integerNegate :: Integer -> Integer
+integerAbs :: Integer -> Integer
 integerDivMod# :: Integer -> Integer -> (# Integer, Integer #)
 integerQuotRem# :: Integer -> Integer -> (# Integer, Integer #)
 
 integerToBigNatSign# :: Integer -> (# Int#, BigNat# #)
 integerFromBigNatSign# :: Int# -> BigNat# -> Integer
 integerFromBigNat# :: BigNat# -> Integer
+integerToNatural :: Integer -> Natural
+integerFromNatural :: Natural -> Integer


=====================================
libraries/ghc-bignum/src/GHC/Num/Natural.hs-boot
=====================================
@@ -16,8 +16,12 @@ naturalToWord# :: Natural -> Word#
 naturalFromWord# :: Word# -> Natural
 naturalFromBigNat# :: BigNat# -> Natural
 naturalToBigNat# :: Natural -> BigNat#
+
+naturalZero :: Natural
 naturalMul :: Natural -> Natural -> Natural
 naturalRem :: Natural -> Natural -> Natural
-naturalIsZero :: Natural -> Bool
 naturalShiftR# :: Natural -> Word# -> Natural
+
+naturalIsZero :: Natural -> Bool
 naturalTestBit# :: Natural -> Word# -> Bool#
+naturalEq# :: Natural -> Natural -> Bool#


=====================================
libraries/integer-gmp/src/GHC/Integer/GMP/Internals.hs
=====================================
@@ -32,6 +32,8 @@ module GHC.Integer.GMP.Internals
     , gcdExtInteger
     , lcmInteger
     , sqrInteger
+    , powModInteger
+    , recipModInteger
 
       -- ** Additional conversion operations to 'Integer'
     , wordToNegInteger
@@ -186,6 +188,18 @@ lcmInteger = I.integerLcm
 sqrInteger :: Integer -> Integer
 sqrInteger = I.integerSqr
 
+{-# DEPRECATED recipModInteger "Use integerRecipMod# instead" #-}
+recipModInteger :: Integer -> Integer -> Integer
+recipModInteger x m = case I.integerRecipMod# x (I.integerToNatural m) of
+   (# y |    #) -> I.integerFromNatural y
+   (#   | () #) -> 0
+
+{-# DEPRECATED powModInteger "Use integerPowMod# instead" #-}
+powModInteger :: Integer -> Integer -> Integer -> Integer
+powModInteger b e m = case I.integerPowMod# b e (I.integerToNatural m) of
+   (# r  | #) -> I.integerFromNatural r
+   (# | () #) -> 0
+
 {-# DEPRECATED wordToNegInteger "Use integerFromWordNeg# instead" #-}
 wordToNegInteger :: Word# -> Integer
 wordToNegInteger = I.integerFromWordNeg#


=====================================
testsuite/tests/lib/integer/all.T
=====================================
@@ -8,7 +8,8 @@ test('IntegerConversionRules', [], makefile_test, ['IntegerConversionRules'])
 test('gcdInteger', normal, compile_and_run, [''])
 test('gcdeInteger', normal, compile_and_run, [''])
 test('integerPowMod', [], compile_and_run, [''])
-test('integerGcdExt', [omit_ways(['ghci'])], compile_and_run, [''])
+test('integerGcdExt', [], compile_and_run, [''])
+test('integerRecipMod', [], compile_and_run, [''])
 
 # skip ghci as it doesn't support unboxed tuples
 test('integerImportExport', [omit_ways(['ghci'])], compile_and_run, [''])


=====================================
testsuite/tests/lib/integer/integerGmpInternals.hs
=====================================
@@ -12,9 +12,6 @@ import GHC.Base
 import GHC.Num.Integer
 import qualified GHC.Num.Integer as I
 
-recipModInteger :: Integer -> Integer -> Integer
-recipModInteger = I.recipModInteger
-
 -- FIXME: Lacks GMP2 version
 powInteger :: Integer -> Word -> Integer
 powInteger x e = x^e
@@ -25,7 +22,6 @@ main = do
     print $ powInteger 12345 0
     print $ powInteger 12345 1
     print $ powInteger 12345 30
-    print $ [ (x,i) | x <- [-7..71], let i = recipModInteger x (2*3*11*11*17*17), i /= 0 ]
 
     putStrLn "\n# nextPrimeInteger"
     print $ I.nextPrimeInteger b


=====================================
testsuite/tests/lib/integer/integerGmpInternals.stdout
=====================================
@@ -3,7 +3,6 @@
 1
 12345
 555562377826831043419246079513769804614412256811161773362797946971665712715296306339052301636736176350153982639312744140625
-[(-7,149867),(-5,167851),(-1,209813),(1,1),(5,41963),(7,59947),(13,177535),(19,143557),(23,182447),(25,134281),(29,7235),(31,33841),(35,95915),(37,113413),(41,61409),(43,24397),(47,174101),(49,158431),(53,193979),(59,188477),(61,185737),(65,35507),(67,118999),(71,186173)]
 
 # nextPrimeInteger
 2988348162058574136915891421498819466320163312926952423791023078876343


=====================================
testsuite/tests/lib/integer/integerPowMod.hs
=====================================
@@ -1,3 +1,6 @@
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE MagicHash #-}
+
 module Main (main) where
 
 import Data.List (group)
@@ -7,22 +10,33 @@ import Control.Monad
 
 import GHC.Word
 import GHC.Base
-import GHC.Natural
+import GHC.Num.Natural
+import GHC.Num.Integer
+
+integerPowMod :: Integer -> Integer -> Integer -> Maybe Integer
+integerPowMod b e m = case integerPowMod# b e (fromIntegral m) of
+   (# | () #) -> Nothing
+   (# r  | #) -> Just (fromIntegral r)
 
 main :: IO ()
 main = do
-    print $ powModNatural b e m
-    print $ powModNatural b e (m-1)
+    print $ naturalPowMod b e m
+    print $ naturalPowMod b e (m-1)
+
+    print $ integerPowMod b e m
+    print $ integerPowMod b e (m-1)
+
+    print $ integerPowMod b (-e) m
+    print $ integerPowMod b (-e) (m-1)
+
+    print $ integerPowMod (-b) e m
+    print $ integerPowMod (-b) e (m-1)
+
+    print $ integerPowMod (-b) (-e) m
+    print $ integerPowMod (-b) (-e) (m-1)
 
   where
+    b,e,m :: Num a => a
     b = 2988348162058574136915891421498819466320163312926952423791023078876139
     e = 2351399303373464486466122544523690094744975233415544072992656881240319
     m = 10^(40::Int)
-
-    x = 5328841272400314897981163497728751426
-    y = 32052182750761975518649228050096851724
-
-    b1024 = roll (map fromIntegral (take 128 [0x80::Int .. ]))
-
-    roll :: [Word8] -> Integer
-    roll = GHC.Base.foldr (\b a -> a `shiftL` 8 .|. fromIntegral b) 0


=====================================
testsuite/tests/lib/integer/integerPowMod.stdout
=====================================
@@ -1,2 +1,10 @@
 1527229998585248450016808958343740453059
 682382427572745901624116300491295556924
+Just 1527229998585248450016808958343740453059
+Just 682382427572745901624116300491295556924
+Just 9710805908340105786808462779613285007339
+Nothing
+Just 8472770001414751549983191041656259546941
+Just 9317617572427254098375883699508704443075
+Just 289194091659894213191537220386714992661
+Nothing


=====================================
testsuite/tests/lib/integer/integerRecipMod.hs
=====================================
@@ -0,0 +1,33 @@
+{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples, TupleSections #-}
+
+module Main (main) where
+
+import Data.List (group)
+import Data.Bits
+import Data.Word
+import Data.Maybe
+import Control.Monad
+
+import GHC.Word
+import GHC.Base
+import GHC.Num.Integer
+import GHC.Num.Natural
+import qualified GHC.Num.Integer as I
+
+recipModInteger :: Integer -> Natural -> Maybe Natural
+recipModInteger x m = case I.integerRecipMod# x m of
+   (# y |    #) -> Just y
+   (#   | () #) -> Nothing
+
+main :: IO ()
+main = do
+   let
+      f x = case recipModInteger x (2*3*11*11*17*17) of
+               y -> fmap (x,) y
+
+   -- positive modulo
+   print $ mapMaybe f [-7..71]
+
+   -- modulo == 1 or 0
+   print (recipModInteger 77 1)
+   print (recipModInteger 77 0)


=====================================
testsuite/tests/lib/integer/integerRecipMod.stdout
=====================================
@@ -0,0 +1,3 @@
+[(-7,149867),(-5,167851),(-1,209813),(1,1),(5,41963),(7,59947),(13,177535),(19,143557),(23,182447),(25,134281),(29,7235),(31,33841),(35,95915),(37,113413),(41,61409),(43,24397),(47,174101),(49,158431),(53,193979),(59,188477),(61,185737),(65,35507),(67,118999),(71,186173)]
+Nothing
+Nothing



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/3c9beab75aaa5fbbb11132c99e2af114f322152f...8dd4f40512bb18e296280acde0507b4233a27b69

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/3c9beab75aaa5fbbb11132c99e2af114f322152f...8dd4f40512bb18e296280acde0507b4233a27b69
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20201002/7cbd5653/attachment-0001.html>


More information about the ghc-commits mailing list