当代码似乎错误时,Scheme中的Miller-Rabin过程为什么工作?
我通过SICP工作。在练习1.28中,关于Miller-Rabin试验。我有这个代码,我知道它是错误的,因为它没有遵循练习的说明当代码似乎错误时,Scheme中的Miller-Rabin过程为什么工作?,scheme,lisp,sicp,Scheme,Lisp,Sicp,我通过SICP工作。在练习1.28中,关于Miller-Rabin试验。我有这个代码,我知道它是错误的,因为它没有遵循练习的说明 (define (fast-prime? n times) (define (even? x) (= (remainder x 2) 0)) (define (miller-rabin-test n) (try-it (+ 1 (random (- n 1))
(define (fast-prime? n times)
(define (even? x)
(= (remainder x 2) 0))
(define (miller-rabin-test n)
(try-it (+ 1 (random (- n 1)))))
(define (try-it a)
(= (expmod a (- n 1) n) 1))
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(if (and (not (= exp (- m 1))) (= (remainder (square exp) m) 1))
0
(remainder (square (expmod base (/ exp 2) m)) m)))
(else
(remainder (* base (expmod base (- exp 1) m)) m))))
(cond ((= times 0) true)
((miller-rabin-test n) (fast-prime? n (- times 1)))
(else false)))
在它中,我测试指数的平方是否与1模n一致。根据
我所读到的和我所看到的其他正确的实现都是错误的。我应该测试一下
完整的数字如下所示:
...
(square
(trivial-test (expmod base (/ exp 2) m) m))
...
问题是我已经用很多素数和大卡米切尔数测试过了,
它似乎给出了正确的答案,尽管速度慢了一点。我不明白为什么会这样
似乎有效 在我看来,您仍然得到了正确的答案,因为在
expmod
的每次迭代中,您都会检查上一次迭代的条件。您可以尝试使用expmod
中的display
函数调试exp
值。事实上,您的代码与之没有太大区别。您的函数版本“有效”只是因为您运气好。尝试这个实验:评估(fast prime?561 3)
一百次。根据函数选择的随机见证,有时返回true,有时返回false。当我这样做的时候,我得到了12对和88错,但是你可能会得到不同的结果,这取决于你的随机数生成器
> (let loop ((k 0) (t 0) (f 0))
(if (= k 100) (values t f)
(if (fast-prime? 561 3)
(loop (+ k 1) (+ t 1) f)
(loop (+ k 1) t (+ f 1)))))
12
88
我面前没有SICP——我的副本在家里——但我可以告诉你进行米勒-拉宾素性测试的正确方法
您的expmod
功能不正确;没有理由将指数平方。以下是执行模幂运算的适当函数:
(define (expm b e m) ; modular exponentiation
(let loop ((b b) (e e) (x 1))
(if (zero? e) x
(loop (modulo (* b b) m) (quotient e 2)
(if (odd? e) (modulo (* b x) m) x)))))
然后Gary Miller的强伪素数测试,这是您的try it
测试的一个强版本,其中有一个证人a可以证明每个复合n的复合性,如下所示:
(define (strong-pseudoprime? n a) ; strong pseudoprime base a
(let loop ((r 0) (s (- n 1)))
(if (even? s) (loop (+ r 1) (/ s 2))
(if (= (expm a s n) 1) #t
(let loop ((r r) (s s))
(cond ((zero? r) #f)
((= (expm a s n) (- n 1)) #t)
(else (loop (- r 1) (* s 2)))))))))
假设扩展Riemann假设,从2到n-1的每一个a测试将证明(实际的、确定性的证明,而不仅仅是素数的概率估计)素数n的素数,或者至少确定一个a是复合n的复合性的见证。迈克尔·拉宾证明了若n是复合的,从2到n-1的a中至少有四分之三是复合性的见证人,所以测试k个随机基证明了,但并没有证明,素数n的素数概率为4−K因此,Miller-Rabin素性测试的实现:
(define (prime? n k)
(let loop ((k k))
(cond ((zero? k) #t)
((not (strong-pseudoprime? n (random (+ 2 (- n 3))))) #f)
(else (loop (- k 1))))))
始终正常工作的:
> (let loop ((k 0) (t 0) (f 0))
(if (= k 100) (values t f)
(if (prime? 561 3)
(loop (+ k 1) (+ t 1) f)
(loop (+ k 1) t (+ f 1)))))
0
100
我知道你的目的是研究SICP而不是编写素数测试,但如果你对素数编程感兴趣,我会在我的博客上谦虚地推荐你,该博客讨论了Miller-Rabin测试以及其他主题。你也应该知道,有比随机Miller Rabin更好的(更快,更不可能报告错误的结果)素性测试可用。你所说的
琐碎测试是什么意思?
?我知道我的代码是错误的,但被愚弄了,因为当你尝试许多时间时,它会给出“好”的结果。每一个素数有10个(这是我在提问前测试时使用的最小值),它在1000个素数中只给出3个不正确的结果,这解释了为什么我“总是”得到正确的答案。样本量是我的问题。我被随机性愚弄了-P谢谢你的回答,下次我会记得用大样本测试任何概率算法。谢谢你的解释。SICP中的练习未能清楚地传达这样一个事实(对于我们,非数学家!),即米勒的测试仍然是一个概率测试:)。因此,在正确地解决了这个问题后,我也在为重复测试运行和长测试序列的古怪答案而挣扎:)