【问题标题】:SICP Exercise 1.28 - Miller-Rabin - "at least half the numbers will reveal a nontrivial square root of 1 modulo n"SICP 练习 1.28 - Miller-Rabin - “至少一半的数字将显示 1 模 n 的非平凡平方根”
【发布时间】:2019-09-21 23:15:56
【问题描述】:

SICP 练习 1.28

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-11.html#%_thm_1.28

费马检验的一种变体,不能被愚弄 称为 Miller-Rabin 检验(Miller 1976;Rabin 1980)。这开始 来自费马小定理的另一种形式,它指出 如果 n 是素数并且 a 是小于 n 的任何正整数,则 a 的 (n - 1) 次幂等于 1 模 n。去测试 通过米勒-拉宾检验,我们随机选择一个数 n 的素数 数字 a 如果n是一个非素数的奇数,那么, 对于至少一半的数字 a (这就是为什么 Miller-Rabin 测试不能被愚弄。)将 expmod 过程修改为 如果它发现一个非平凡的平方根 1,则发出信号,并使用它来 使用类似于 费马测试。通过测试各种已知的素数和 非素数。提示:制作 expmod 信号的一种方便方法是 它返回 0。

我已经编写了自己的解决方案,其结果与此处提供的解决方案一致:

http://community.schemewiki.org/?sicp-ex-1.28

15 是一个非素数的奇数,因此对于从114 的至少一半数字a,我预计计算expmod(a, 14, 15) 将显示一个模数为n 的非平凡平方根,由expmod返回0表示。

但是,这些是我得到的结果:

(expmod 1 14 15)
> 1
(expmod 2 14 15)
> 4
(expmod 3 14 15)
> 9
(expmod 4 14 15)
> 0
(expmod 5 14 15)
> 10
(expmod 6 14 15)
> 6
(expmod 7 14 15)
> 4
(expmod 8 14 15)
> 4
(expmod 9 14 15)
> 6
(expmod 10 14 15)
> 10
(expmod 11 14 15)
> 0
(expmod 12 14 15)
> 9
(expmod 13 14 15)
> 4
(expmod 14 14 15)
> 1

可以看出,这些结果中只有 2 个是 0,与预期的至少 7 个相比相差甚远。

我误解了声明吗?我是一个彻头彻尾的白痴吗?代码错了吗? SICP错了吗?非常感谢。

编辑 1:要求我提供我正在使用的确切代码。就是这样,虽然我基本上只是复制了我链接到的解决方案,并将 remainder 别名为 mod 因为这是我的解释器所说的。

 (define (square x) (* x x))

 (define remainder mod)

 (define (miller-rabin-expmod base exp m) 
   (define (squaremod-with-check x) 
     (define (check-nontrivial-sqrt1 x square) 
       (if (and (= square 1) 
                (not (= x 1)) 
                (not (= x (- m 1)))) 
           0 
           square)) 
     (check-nontrivial-sqrt1 x (remainder (square x) m))) 
   (cond ((= exp 0) 1) 
         ((even? exp) (squaremod-with-check 
                       (miller-rabin-expmod base (/ exp 2) m))) 
         (else 
          (remainder (* base (miller-rabin-expmod base (- exp 1) m)) 
                     m))))

(define expmod miller-rabin-expmod)

(print (expmod 1 14 15))
(print (expmod 2 14 15))
(print (expmod 3 14 15))
(print (expmod 4 14 15))
(print (expmod 5 14 15))
(print (expmod 6 14 15))
(print (expmod 7 14 15))
(print (expmod 8 14 15))
(print (expmod 9 14 15))
(print (expmod 10 14 15))
(print (expmod 11 14 15))
(print (expmod 12 14 15))
(print (expmod 13 14 15))
(print (expmod 14 14 15))

编辑 2:我现在还手动计算了 expmod(a, 14, 15) 的步骤(它总是通过 exp = 14exp = 7exp = 6exp = 3exp = 3exp = 2exp = 1exp = 0 递归),对于从 1 到 14 的 a 的所有值,我确信只有 a = 4a = 11 遇到 1 的非平凡平方根。所以我倾向于认为 SICP 对此要么是错误的,或者表达不清晰。

【问题讨论】:

  • 您对 expmod 过程的修改很可能存在错误。
  • @JamesKPolk 我没有修改它,我使用了我链接的解决方案中的代码,并且我也使用了我自己的版本,并且它们彼此一致。如果您认为我使用不正确,请检查我自己链接的解决方案。
  • 抱歉,它被读作 a^(n-1),而不是 a^n - 1(按照我链接的 SICP 文本中的格式;我将编辑我的问题)——基本上是检查费马小定理。

标签: scheme primes sicp primality-test


【解决方案1】:

根据@Memes 的回答,我已经为它添加了方案代码:

(define (display-all . vs)
  (for-each display vs))

(define (find-e-k n)
  (define (find-e-k-iter possible-k possible-e)
    (if (= (remainder possible-k 2) 0)
        (find-e-k-iter (/ possible-k 2) (+ possible-e 1))
        (values possible-e possible-k)))
  (find-e-k-iter (- n 1) 0))

; first-witness-case-test: (a ^ k) mod n # 1
(define (first-witness-case-test a k n)
  (not (= (expmod a k n) 1)))

; second-witness-case-test: all a ^ ((2 ^ i) * k) (with i = {0..e-1}) mod n # (n - 1)
(define (second-witness-case-test a e k n)
  (define (second-witness-case-test-iter a i k n)
    (cond ((= i -1) true)
          (else (let ()
                 (define witness (not (= (expmod a (* (fast-expt 2 i) k) n) (- n 1))))
                 (if witness
                 (second-witness-case-test-iter a (- i 1) k n)
                 false)))))
  (second-witness-case-test-iter a (- e 1) k n))

(define (miller-rabin-test n)
  (define (try-it a e k)
    (if (and (first-witness-case-test a k n) (second-witness-case-test a e k n))
        (display-all "is not prime, with a = " a "\n")
        (if (< a (- n 1))
            (try-it (+ a 1) e k)
            (display "is prime\n"))))
  (cond ((< n 2) (display "not prime"))
        ((= (remainder n 2) 0) (display "not prime\n"))
        (else (let ()
               (define-values (e k) (find-e-k n))
               (try-it 1 e k)))))

【讨论】:

    【解决方案2】:

    SICP 是错误的,因为它使用了错误的 Miller–Rabin 见证人定义(参见 Keith Conrad,The Miller–Rabin Test)。特别是下面这行是错误的:

    错误的主张。 也可以证明如果n是一个非素数的奇数,那么对于a

    您可以验证这是错误的,例如当 n = 9 时。

    根据上述参考中的定理2.9,正确的说法应该是这样的:

    正确的说法。 令 n > 1 是一个非素数的奇数。然后我们可以将 n - 1 写为 (2^e)k 使得 e &geq; 1 和 k 是奇数。 (例如,如果 n = 21,我们可以写成 21 - 1 = 20 = (2^2)·5,因此 e = 2 ≥ 1 并且 k = 5 是奇数。) 可以证明,对于至少一半的数字 a

    因此,对于 n = 21,我们可以证明对于至少一半的数字 a

    +----+-----+-------+
    | a  | a^5 |  a^10 | MILLER–RABIN WITNESS? 
    +----+-----+-------+
    |  1 |   1 |     1 | NO, a^5 ≡ 1
    |  2 |  11 |    16 | YES
    |  3 |  12 |    18 | YES
    |  4 |  16 |     4 | YES
    |  5 |  17 |    16 | YES
    |  6 |   6 |    15 | YES
    |  7 |   7 |     7 | YES
    |  8 |   1 |     1 | NO, a^5 ≡ 1
    |  9 |  18 |     9 | YES
    | 10 |  19 |     4 | YES
    | 11 |   2 |     4 | YES
    | 12 |   3 |     9 | YES
    | 13 |  13 |     1 | YES
    | 14 |  14 |     7 | YES
    | 15 |  15 |    15 | YES
    | 16 |   4 |    16 | YES
    | 17 |   5 |     4 | YES
    | 18 |   9 |    18 | YES
    | 19 |  10 |    16 | YES
    | 20 |  20 |     1 | NO, a^5 ≡ 20
    +----+-----+-------+
    

    果然,超过一半的 a

    编辑。 仅作为说明素数的示例,这里是 n = 13 的表。自然不可能有任何 Miller-Rabin 见证 13,因为它是素数;没有非原始性可以见证。由于 n = 13,我们有 n - 1 = 12 = (2^2)·3,所以 e = 2 ≥ 1 且 k = 3 是奇数。因此,正如 Keith Conrad 的说明性论文第 1 页所述,所有 a

    +----+-----+-------+
    | a  | a^3 |   a^6 | MILLER–RABIN WITNESS? 
    +----+-----+-------+
    |  1 |   1 |     1 | NO, a^3 ≡ 1
    |  2 |   8 |    12 | NO, a^6 ≡ 12
    |  3 |   1 |     1 | NO, a^3 ≡ 1
    |  4 |  12 |     1 | NO, a^3 ≡ 12
    |  5 |   8 |    12 | NO, a^6 ≡ 12
    |  6 |   8 |    12 | NO, a^6 ≡ 12
    |  7 |   5 |    12 | NO, a^6 ≡ 12
    |  8 |   5 |    12 | NO, a^6 ≡ 12
    |  9 |   1 |     1 | NO, a^3 ≡ 1
    | 10 |  12 |     1 | NO, a^3 ≡ 12
    | 11 |   5 |    12 | NO, a^6 ≡ 12
    | 12 |  12 |     1 | NO, a^3 ≡ 12
    +----+-----+-------+
    

    【讨论】:

      【解决方案3】:

      我找到了一篇涵盖该测试的论文,并证明了 2 和 n-2 之间超过一半的值将导致 1 的非平凡平方根。(定理 4.1)

      我制作了这段代码来仔细检查它

      (define (print x) (display x) (newline))
      
      (define (assert p) (unless p (error 'assert-failed)))
      
      (define (power-of-two-split m)
        ;; write m = 2^e k
        (let loop ((e 0) (k m))
          (if (even? k)
              (loop (+ e 1) (quotient k 2))
              (cons e k))))
      
      (define (exp/mod a k n)
        ;; a^k (mod n)
        (cond ((= k 0) 1)
              ((= k 1) (modulo a n))
              (else (modulo (* a (exp/mod a (- k 1) n)) n))))
      
      (define (miller-rabin a n)
        (assert (odd? n))
        (assert (= 3 (modulo n 4))) ;; only handles e=1 case, need to use power-of-two-split for full test
        (let ((k (quotient (- n 1) 2)))
          (exp/mod a k n)))
      
      (define (test n)
        (for ((i (in-range 2 (- n 2))))
          (let ((m (miller-rabin i n)))
            (print `(,i -> ,m squared ,(exp/mod m 2 n))))))
      
      (test 15)
      

      它打印以下结果

      (2 -> 8 squared 4)
      (3 -> 12 squared 9)
      (4 -> 4 squared 1)
      (5 -> 5 squared 10)
      (6 -> 6 squared 6)
      (7 -> 13 squared 4)
      (8 -> 2 squared 4)
      (9 -> 9 squared 6)
      (10 -> 10 squared 10)
      (11 -> 11 squared 1)
      (12 -> 3 squared 9)
      

      因此,对照米勒拉宾见证人的正式定义,他们实际上是所有温特斯:

      定义 2.3。对于奇数 n > 1,用 k 奇数写 n − 1 = 2^ek 并选择 a ∈ {1, . . . , n - 1}。我们说 a 是 n 的 Miller-Rabin 证人,如果 in 的所有同余项都是错误的: * a^k = 1 mod n 和 a^{(2^i)k} = −1 mod n 对于所有 i ∈ {0, . . . , e - 1}.

      您可以看到“m”列中没有一个值是 1,平方列中没有一个值是 14。所以他们都是见证者,所以 >50% 是。

      执行“check-nontrivial-sqrt1”的代码与 n=3(mod 4)的这种特殊情况无关,因为在这种情况下 e=1。


      更新:

      我刚刚意识到为什么我们有很多证人但我们并不总是从他们中找到一个平方根:

      米勒-拉宾证人背后的想法是找到一个意想不到的 1 mod n 的平方根。这并不总是我们实际发现的,因为对于素数 n 的前提 a n−1 ≡ 1 mod n 可能实际上对于复合 n 并不成立。

      这是一个 a^(n-1) (mod n) 的表格,对于 n=15

      (2 -> 4)
      (3 -> 9)
      (4 -> 1)
      (5 -> 10)
      (6 -> 6)
      (7 -> 4)
      (8 -> 4)
      (9 -> 6)
      (10 -> 10)
      (11 -> 1)
      (12 -> 9)
      

      如您所见,同余 a^(n-1) = 1 (mod n) 实际上只成立两次。

      【讨论】:

      • 我很难理解见证人的定义与 expmod 标记非平凡根 1 的关系。让我们关注一个例子。你说2是证人。我已经手动检查并同意。那么为什么expmod 不标记它呢?根据 SICP 的定义,我看不出它会如何。 (expmod 2 14 15) = 4,通过(expmod 2 7 15) = 8,通过(expmod 2 6 15) = 4,通过(expmod 2 3 15) = 8,通过(expmod 2 2 15) = 4,通过(expmod 2 1 15) = 2,通过(expmod 2 0 15) = 1。所以从来没有一个平方步骤可以发现一个非平凡的根 1。所以a = 2 没有被标记。正确的? SICP错了吗?
      • 我稍微调整了代码以打印出 1 的实际非平凡平方根,而我得到的 1 不到一半。所以我必须道歉,我不能真正回答原来的问题,我不完全理解。
      • 添加了一点关于为什么我们并不总是找到 1 的平方根。现在很清楚了。
      • 对不起,我没有跟上,你能回答我在上一条评论中给出的例子的问题吗?
      【解决方案4】:

      费马检验的一种变体被称为米勒-拉宾检验(Miller-Rabin 检验)(Miller 1976;Rabin 1980)。这从费马小定理的另一种形式开始,该定理指出,如果 n 是质数且 a 是小于 n 的任何正整数,则 a 的 (n - 1) 次幂等于 1 模 n。

      • n 是素数,a a^(n-1) = 1 (mod n)

      为了通过 Miller-Rabin 检验测试数字 n 的素数,我们选择一个随机数 a

      所以随机选择一个并检查 a^(n-1) = 1 (mod n)。如果它是 not 那么你知道 n 不是素数。

      但是,每当我们在 expmod 中执行平方步骤时,我们都会检查是否发现了“1 模 n 的非平凡平方根”,即不等于 1 或 n - 1 的数,其平方等于 1 模 n。

      这是关于在 expmod 函数中添加的额外检查。这可能是你忽略的事情。

      可以证明,如果存在这样一个 1 的非平凡平方根,则 n 不是素数。

      让我们详细讨论一下。 1 的非平凡平方根将是一个数 x,使得 x^2 = 1 (mod n)。并且 x 不是 1 或 -1。

      为什么其中之一表明 n 不是素数?

      我们知道 x^2 - 1 = (x - 1)(x + 1) 和 (working modulo n) x-1 和 x+1 都不为零,但它们的乘积为零。这意味着我们有一个复合模数,您可以通过取这两个值的 GCD 来分解它。

      还可以证明,如果 n 是一个非素数的奇数,那么,对于 a

      这又是在讨论向 expmod 函数的平方分支添加内部测试。

      修改 expmod 过程以在发现非平凡平方根 1 时发出信号,并使用此过程通过类似于 fermat-test 的过程来实现 Miller-Rabin 检验。通过测试各种已知的素数和非素数来检查你的程序。提示:产生 expmod 信号的一种方便方法是让它返回 0。

      希望对您有所帮助!询问您是否需要更多指导。

      【讨论】:

      • 非常感谢您的回答,虽然我不确定它是否解决了我的困难。我没有忽略额外的检查——事实上我已经按照要求实施了。当检查失败时,它会导致expmod 返回0。这也是由我链接的解决方案实现的(尽管他们调用函数miller-rabin-expmod 而不是expmod)。正如我所看到的,我上面测试的更多a 值应该返回0(至少7)——这是正确的吗?如果是这样,您能否举例说明应该返回 0 但没有返回的值之一?
      • 如果你愿意,我可以,但我几乎只是将我链接到的代码粘贴到我的问题中。
      • 哦,我认为您只是稍微误解了大胆的主张。 'a' 的大多数选择将导致见证(非平凡的 1 平方根)。例如,您选择的那个。但是您是否期望一半的 expmod 计算返回零?这不是声称的。
      • 请注意,a 的某些选择可能是“骗子”,这意味着没有为该基数找到 1 的非平凡平方根。
      • “你选择的那个”是什么意思?我使用了从 1 到 14 的所有 a 值。其中只有两个导致标志被升起。
      猜你喜欢
      • 1970-01-01
      • 2019-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多