Scheme 米勒-拉宾试验(SICP 1.28)

Scheme 米勒-拉宾试验(SICP 1.28),scheme,primes,sicp,modular-arithmetic,primality-test,Scheme,Primes,Sicp,Modular Arithmetic,Primality Test,费马测试的一个变体是米勒-拉宾测试(Miller 1976;拉宾1980),它不能被愚弄。这是从Fermat小定理的另一种形式开始的,该定理指出,如果n是素数且a是小于n的任何正整数,则提升到(n-1)次方的a与模n的1全等 为了通过Miller-Rabin测试测试数字n的素性,我们选择一个小于n的随机数a,并使用expmod过程将a提升到(n-1)阶幂模n。然而,每当我们在expmod中执行平方步骤时,我们都会检查是否发现了一个“1模n的非平凡平方根”,即一个不等于1或n-1的数,其平方等于1

费马测试的一个变体是米勒-拉宾测试(Miller 1976;拉宾1980),它不能被愚弄。这是从Fermat小定理的另一种形式开始的,该定理指出,如果n是素数且a是小于n的任何正整数,则提升到(n-1)次方的a与模n的1全等

为了通过Miller-Rabin测试测试数字n的素性,我们选择一个小于n的随机数a,并使用
expmod
过程将a提升到(n-1)阶幂模n。然而,每当我们在
expmod
中执行平方步骤时,我们都会检查是否发现了一个“1模n的非平凡平方根”,即一个不等于1或n-1的数,其平方等于1模n

可以证明,如果1的非平凡平方根存在,那么n不是素数。还可以证明,如果n是不是素数的奇数,那么,对于至少一半的数a 修改
expmod
程序,以在发现非平凡平方根为1时发出信号,并使用类似于
fermat测试的程序来执行Miller-Rabin测试。通过测试各种已知素数和非素数来检查您的程序。提示:使
expmod
信号返回0是一种方便的方法

这就是我目前所拥有的

(define (square x) (* x x))
(define (even? n) (= (remainder n 2)))

(define (expmod-signal b n m)
  (define (check a)
    (and (not (= a 1))
         (not (= a (- n 1)))
         (= (square a) (remainder 1 n))))
  (cond ((= n 0) 1)
        ((check b) 0)
        ((even? n) (remainder (square (expmod-signal b (/ n 2) m)) m))
        (else (remainder (* b (expmod-signal b (- n 1) m)) m))))

(define (miller-rabin n)
  (define (fail? n a)
    (or (= n 0) (not (= n a))))
  (define (try a)
    (cond ((= a 1) #t)
          ((fail? (expmod-signal a (- n 1) n) a) #f)
          (else (try (- a 1)))))
  (try (- n 1)))

我想我正确地实现了
miller-rabin
,但我不明白修改后的
expmod
应该如何工作。你是在方格前还是方格后查号码?通过阅读问题我不知道。

我通过使用
expmod信号
内部的
expmod
的原始定义解决了这个问题。在我的测试中,
expmod信号
自然地返回零并干扰测试。我误解了check函数,“其平方等于1模n”意味着检查a^2%m=1
。此检查函数的工作方式是,如果参数是1 mod n的非平凡平方根,则返回0,否则返回参数。如果返回零,则零将通过
expmod信号的剩余部分传播并返回

(define (square x) (* x x))
(define (even? n) (= (remainder n 2)))

(define (expmod base exp m)
  (cond ((= exp 0) 1)
        ((even? exp) (remainder (square (expmod base (/ exp 2) m)) m))
        (else (remainder (* base (expmod base (- exp 1) m)) m))))

(define (expmod-signal b n m)
  (define (check a)
    (if (and (not (= a 1))
             (not (= a (- n 1)))
             (= (remainder (square a) n) 1))
        0
        a))
  (cond ((= n 0) 1)
        ((even? n) (remainder (square (check (expmod b (/ n 2) m))) m))
        (else (remainder (* b (expmod b (- n 1) m)) m))))

(define (miller-rabin n)
  (define (fail? a)
    (or (= a 0) (not (= a 1))))
  (define (try a)
    (cond ((= a 1) #t)
          ((fail? (expmod-signal a (- n 1) n)) #f)
          (else (try (- a 1)))))
  (try (- n 1)))