Miller-Rabin测试(SICP 1.28)

时间:2019-05-17 02:29:10

标签: scheme primes sicp modular-arithmetic primality-test

  不能被愚弄的费马测验的一个变种叫做米勒-拉宾测验(Miller 1976; Rabin 1980)。这从费马小定理的另一种形式开始,该定理指出,如果 n 是质数,并且 a 是小于 n 的任何正整数,则提高到(n-1)次幂的 a 1 取模 n 的幂相同。

     

要通过Miller-Rabin检验检验数字 n 的素数,我们选择一个小于 n 的随机数 a 并提高使用expmod过程将 a 转换为(n-1) st次幂模 n 。但是,每当我们在expmod中执行平方步骤时,我们都会检查是否发现了“ 1 取模 n 的非平凡平方根”,即,一个不等于 1 n-1 的数字,其平方等于 1 n 取模。

     

有可能证明,如果存在这样的 1 非平凡平方根,则 n 不是素数。也有可能证明,如果 n 是不是质数的奇数,则至少对数字 a 的一半,计算 a < sup> n-1 这样将揭示 1 取模 n 的非平凡平方根。 (这就是为什么不能欺骗Miller-Rabin检验的原因。)

     

修改expmod过程以发出是否发现 1 的平凡根的信号,并使用该过程通过类似于fermat-test的过程来实现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应该如何工作。您检查方格之前或之后的数字吗?从阅读问题中我不知道。

1 个答案:

答案 0 :(得分:1)

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

(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)))