multiplicative inverse of modulo m in scheme

我与影子孤独终老i 提交于 2019-12-02 07:37:43

问题


I've written the code for multiplicative inverse of modulo m. It works for most of the initial cases but not for some. The code is below:

(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)))))))

For example it gives correct values for (inverse 5 11) -> 9 (inverse 9 11) -> 5 (inverse 7 11 ) - > 8 (inverse 8 12) -> #f but when i give (inverse 5 12) it produces #f while it should have been 5. Can you see where the bug is?

Thanks for any help.


回答1:


Does it have to be precisely that algorithm? if not, try this one, taken from 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))))

It works as expected:

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



回答2:


The algorithm you quoted is Algorithm 9.4.4 from the book Prime Numbers by Richard Crandall and Carl Pomerance. In the text of the book they state that the algorithm works for both prime and composite moduli, but in the errata to their book they correctly state that the algorithm works always for prime moduli and mostly, but not always, for composite moduli. Hence the failure that you found.

Like you, I used Algorithm 9.4.4 and was mystified at some of my results until I discovered the problem.

Here's the modular inverse function that I use now, which works with both prime and composite moduli, as long as its two arguments are coprime to one another. It is essentially the extended Euclidean algorithm that @OscarLopez uses, but with some redundant calculations stripped out. If you like, you can change the function to return #f instead of throwing an error.

(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)))))))



回答3:


I think this is the Haskell code on that page translated directly into 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)))))))

It looks like you're trying to convert it from recursive to tail-recursive, which is why things don't match up so well.




回答4:


These two functions below can help you as well.

Theory

Here’s how we find the multiplicative inverse d. We want e*d = 1(mod n), which means that ed + nk = 1 for some integer k. So we’ll write a procedure that solves the general equation ax + by = 1, where a and b are given, x and y are variables, and all of these values are integers. We’ll use this procedure to solve ed + nk = 1 for d and k. Then we can throw away k and simply return 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))))))

This function is a general solution to an equation in form of ax+by=1 where a and b is given.The inverse-mod function simply uses this solution and returns the inverse.

 (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))))))

Some test cases are :

(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


来源:https://stackoverflow.com/questions/13096491/multiplicative-inverse-of-modulo-m-in-scheme

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!