我已经编写了模数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在哪里吗?
感谢您的帮助。
答案 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