Scheme 格式中模m的乘法逆
我已经写了模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))
(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
。在Schemet中,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