Scheme 格式中模m的乘法逆

Scheme 格式中模m的乘法逆,scheme,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))

我已经写了模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。你能看到臭虫在哪里吗


谢谢您的帮助。

我想这是该页面上的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)))))))

看起来您正试图将它从递归转换为尾部递归,这就是为什么事情不那么匹配的原因。

它必须是精确的算法吗?如果没有,请尝试以下内容:

它按预期工作:

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

您引用的算法是Richard Crandall和Carl Pomerance的《素数》一书中的算法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)))))))

下面这两个功能也可以帮助您

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

此函数是ax+by=1形式的方程的通解,其中给出了a和b。逆mod函数仅使用此解并返回逆mod

一些测试用例包括:

(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

你在用什么算法?这一次我很难找到这里介绍的算法和你的代码之间的对应关系。它使用p和q没有帮助,而使用x和m(q与它们的q不对应)。我没有一个方案实现来尝试它,所以它没有经过测试。但是为什么它不编译呢?我使用的是R6RS中的函数(我没有看到那里的
,它有
mod
div
),它有一些基本语法错误。此外,我首先尝试将相同的算法从Haskell转换为Scheme,但它没有返回正确的结果。我在下面的答案中找到并发布的算法确实有效,并返回正确的值。如果@JohnClements存在,他会说:“测试用例!测试用例!”*叹息*。请不要发布未经测试的代码。我修复了我的代码。正如我所说,我没有一个计划的实施。我通过将其翻译成Emacs Lisp、调试I并将其翻译回来来测试它。我想现在是对的。嗨,我把
t
子句改为使用
else
。在Scheme
t中,t
未绑定到真值。
(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))))))
 (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