- 论坛徽章:
- 0
|
Exercise 1.28. 答案
- (define (mr-test n m)
- (define (pot2 m)
- (letrec ((f (lambda (e o)
- (if (even? o) (f (+ e 1) (/ o 2))
- (cons e o)))))
- (f 0 m)))
-
- (define (make-test-fun)
- (define (second-check b e)
- (cond ((= (- n 1) b) #t)
- ((= 1 b) #f)
- ((= e 1) #f)
- (else (second-check (modulo (* b b) n) (- e 1)))))
-
- (let* ((t (pot2 (- n 1))) (e (car t)) (o (cdr t)))
- (lambda ()
- (let* ((r (+ (random (- n 1)) 1)) (b (powmod r o n)))
- (cond ((= 1 b) #t)
- ((= 0 e) #f)
- ((= (- n 1) b) #t)
- (else (second-check b e)))))))
-
- (let ((f (make-test-fun)))
- (letrec ((loop (lambda (m)
- (cond ((= m 0) #t)
- ((f) (loop (- m 1)))
- (else #f)))))
- (loop m))))
复制代码
对 Carmichael 数试一下效果:
- >(map (lambda (x) (mr-test x 5)) '(561 1105 1729 2465 2821 6601))
- (#f #f #f #f #f #f)
复制代码
======================================================================
理论分析:
- 如果 n 是个素数,a in [0, n). 根据 Fermat 小定理,有 a^(n-1)=1 (mod n)。
- n-1 是偶数,可以写成 2^mk 的形式,其中 k 是奇数。于是 a^(n-1)=1 可以改写为 a^(2^m k)。
- 设 b=a^k,考虑以下序列
B=( b, b^2, b^8, ..., b^(2^m k) ) (mod n)
序列中的每个均是其后继模 n 意义下的平方根。
- 当 n 为素数时, 模 n 意义下, 1 仅有两个平方根 1 和 -1 (这是 MR 测试用来区分素数、合数的关键。对于合数 n,1 的平方根可以多于两个)。
- B 序列可能的模式为
模式 1:(? ? ? ... ? ? ? -1 1 ... 1)
模式 2:(1 1 1 ... 1 1 1 1 1 ... 1)
其中 `?' 为 1, -1 以外的数,而且第一种模式包括 (-1, 1, 1, ..., 1)
- mr 测试的大致步骤为,依次计算 B 序列中的数(除了最后一个),
- 如果一上来就是 1,则是模式 2,可以马上返回,概率推断 n 为素数。
- 如果在途中碰到一个 -1,则是模式 1, 可以马上返回,概率推断 n 为素数。
- 如果在途中遇到 1(但不是B0),则不是前述两种模式,必定为合数。
- 如果在途中一直没有碰到 1, -1,则计算到倒数第二项终止。由于倒数第二项是末项的平方根,但不是 1,-1,所以末项必定不是 1, 从而 n 也必定是个合数。
代码说明:
- pot2 返回一对 cons e.o,如果 n=2^m k,则 e=m, k=o.
- make-test-fun 的返回值是一个函数,包含了必要的参数。之后每执行其返回值一次,就进行了一次随机的 mr-test.
- make-test-fun 中的 second-check 是对序列检查的第二部分(对 B0 的检查比较特殊,之后的检查是 second-check)。
- mr-test 的流程为用 make-test-fun 生成测试函数,并绑定在 f 上。用 loop 函数实现循环测试。
[ 本帖最后由 win_hate 于 2008-9-15 10:50 编辑 ] |
|