方案中模m的乘法逆

时间:2012-10-27 01:37:16

标签: scheme

我已经编写了模数m的乘法逆的代码。它适用于大多数初始情况但不适用于某些情况。代码如下:

(define (inverse x m)
    (let loop ((x (modulo x m)) (a 1))
      (cond ((zero? x) #f) ((= x 1) a)
            (else (let ((q (- (quotient m x))))
                    (loop (+ m (* q x)) (modulo (* q a) m)))))))

例如,它为(逆5 11) - >给出了正确的值。 9(逆9 11) - > 5(逆7 11) - > 8(逆8 12) - > #f但是当我给出(逆5 12)它会产生#f而它应该是5.你能看到bug在哪里吗?

感谢您的帮助。

4 个答案:

答案 0 :(得分:2)

你引用的算法是Richard Crandall和Carl Pomerance所着的 Prime Numbers 一书中的算法9.4.4。在本书的文本中,他们指出该算法适用于素数模型和复合模量,但在他们的书的勘误表中,他们正确地指出算法总是用于素数模量,并且大多数(但不总是)对于复合模量。因此你找到了失败。

和你一样,我使用了算法9.4.4,并且在我发现问题之前对我的一些结果感到困惑。

这是我现在使用的模块化反函数,它既可以使用素数模型,也可以使用复合模数,只要它的两个参数彼此互相参照即可。它本质上是@OscarLopez使用的扩展欧几里德算法,但是有一些冗余计算被剥离了。如果您愿意,可以更改函数以返回#f而不是抛出错误。

(define (inverse x m)
  (let loop ((x x) (b m) (a 0) (u 1))
    (if (zero? x)
        (if (= b 1) (modulo a m)
          (error 'inverse "must be coprime"))
        (let* ((q (quotient b x)))
          (loop (modulo b x) x u (- a (* u q)))))))

答案 1 :(得分:1)

是否必须 算法?如果没有,试试这个,取自wikibooks

(define (egcd a b)
  (if (zero? a)
      (values b 0 1)
      (let-values (((g y x) (egcd (modulo b a) a)))
        (values g (- x (* (quotient b a) y)) y))))

(define (modinv a m)
  (let-values (((g x y) (egcd a m)))
    (if (not (= g 1))
        #f
        (modulo x m))))

按预期工作:

(modinv 5 11) ; 9
(modinv 9 11) ; 5
(modinv 7 11) ; 8
(modinv 8 12) ; #f 
(modinv 5 12) ; 5

答案 2 :(得分:0)

我认为这是将该页面上的Haskell代码直接翻译成Scheme:

(define (inverse p q)
  (cond ((= p 0) #f)
        ((= p 1) 1)
        (else
          (let ((recurse (inverse (mod q p) p)))
             (and recurse
                  (let ((n (- p recurse)))
                    (div (+ (* n q) 1) p)))))))

看起来你正试图将它从递归转换为尾递归,这就是为什么事情不能很好地匹配。

答案 3 :(得分:0)

以下这两项功能也可以为您提供帮助。

理论

以下是我们如何找到乘法逆d。我们想要e * d = 1(mod n),这意味着某些整数k的ed + nk = 1。因此,我们将编写一个解决一般方程ax + by = 1的过程,其中给出a和b,x和y是变量,所有这些值都是整数。我们将使用此过程来解决d和k的ed + nk = 1。然后我们可以扔掉k并简单地返回d。 >

(define (ax+by=1 a b)
        (if (= b 0)
            (cons 1 0)
            (let* ((q (quotient a b))
                   (r (remainder a b))
                   (e (ax+by=1 b r))
                   (s (car e))
                   (t (cdr e)))
           (cons t (- s (* q t))))))

这个函数是ax + by = 1形式的方程的一般解,其中a和b给出。逆mod函数只是使用这个解并返回逆。

  

 (define inverse-mod (lambda (a m) 
                  (if (not (= 1 (gcd a m)))
                      (display "**Error** No inverse exists.")
                      (if (> 0(car (ax+by=1 a m)))
                          (+ (car (ax+by=1 a m)) m)
                          (car (ax+by=1 a m))))))

一些测试用例是:

(inverse-mod 5 11) ; -> 9 5*9 = 45 = 1 (mod 11)
(inverse-mod 9 11) ; -> 5
(inverse-mod 7 11) ; -> 8 7*8 = 56 = 1 (mod 11)
(inverse-mod 5 12) ; -> 5 5*5 = 25 = 1 (mod 12)
(inverse-mod 8 12) ; -> error no inverse exists