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的任何正整数,则 提升到第(n-1)次幂的a等于1模n。去测试 由Miller-Rabin检验得出的n的素数,我们选择一个随机数 数a
如果n是不是质数的奇数,则, 对于至少一半的数字a (这就是为什么 无法欺骗Miller-Rabin测试。)将expmod过程修改为 如果发现非平凡平方根为1则发出信号,并使用它来 使用类似于以下步骤的程序执行Miller-Rabin测试 费马测试。通过测试各种已知的质数来检查您的过程 非素数。提示:产生expmod信号的一种简便方法是 返回0。
我已经编写了自己的解决方案,其结果与此处提供的解决方案一致:
http://community.schemewiki.org/?sicp-ex-1.28
15
是一个不是质数的奇数,因此对于a
至1
的数字14
的至少一半,我希望计算expmod(a, 14, 15)
将显示1模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 = 14
,exp = 7
,exp = 6
,exp = 3
,{ {1}},exp = 2
,exp = 1
),对于exp = 0
从1到14的所有值,我确定只有a
和a = 4
遇到一个不平凡的平方根1。因此,我倾向于认为SICP在这方面有误,或者表达不明确。
答案 0 :(得分:2)
SICP是错误的,因为它使用了Miller–Rabin证人的错误定义(请参见Keith Conrad,The Miller–Rabin Test)。特别是,以下行是错误的:
错误的说法。 也有可能证明,如果n是不是质数的奇数,那么至少对a
您可以验证其为假,例如n = 9时。
按照上述参考中的定理2.9,正确的陈述应为:
正确的声明。 让n> 1为非质数。然后我们可以将n-1记为(2 ^ e)k,使得e≥1并且k为奇数。 (例如,如果n = 21,我们可以写成21-1 = 20 =(2 ^ 2)·5,那么e = 2≥1且k = 5是奇数。) 可以证明至少对于a
因此,对于n = 21,我们可以证明至少a <21的一半,我们将拥有a ^ 5≢1和a ^ 5≢20以及a ^ 10≢20。我们得到下表。 (所有值均以21为模):
+----+-----+-------+
| 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 <21的一半以上(实际上,超过75%)满足所有三个全等式a ^ 5≢1,a ^ 5≢20和a ^ 10≢20。 (我们称其为Miller–Rabin见证人;因为他们见证了n不是质数的事实。通常,许多素数检验都依赖于所有素数均具有的某些属性-如果您证明此类属性对某些数均无效,则这个数字不能是素数。见证人越多,素数测试的效果就越好。)
编辑。作为说明素数的一个示例,这是n = 13的表。自然,不可能有任何Miller–Rabin的13位见证人,因为它是素数。没有非原始的见证。由于n = 13,我们有n-1 = 12 =(2 ^ 2)·3,因此e = 2≥1且k = 3是奇数。因此,正如基思·康拉德(Keith Conrad)说明文件的第1页所述,所有a <13将满足三个全等式a ^ 3≡1,a ^ 3≡12,a ^ 6≡12中的至少一个。并且足够确定:>
+----+-----+-------+
| 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
+----+-----+-------+
答案 1 :(得分: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 :(得分:0)
不能被愚弄的费马测验的一个变种叫做米勒-拉宾测验(Miller 1976; Rabin 1980)。这从费马小定理的另一种形式开始,该定理指出,如果n是素数并且a是小于n的任何正整数,则升到(n-1)次幂等于1模n。 / p>
要通过Miller-Rabin检验测试数字n的素数,我们选择一个随机数a
因此随机选择一个,并检查a ^(n-1)= 1(mod n)。如果不是不是,那么您知道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)和(工作模n)x-1和x + 1都不为零,但其乘积为零。这意味着我们有一个复合模量,您可以通过取这两个值的GCD来将其分解。
也有可能证明,如果n是不是质数的奇数,那么对于至少a
这又是在谈论将内部测试添加到expmod函数的平方分支。
修改expmod过程以发出是否发现平凡根为1的信号,并使用该过程以类似于fermat-test的过程实施Miller-Rabin测试。通过测试各种已知的质数和非质数来检查您的过程。提示:生成expmod信号的一种简便方法是使其返回0。
希望有帮助!询问是否需要其他指导。
答案 3 :(得分:0)
我找到了一篇涵盖该测试的论文,并证明了特定结果的证明,即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证人: *对于所有i∈{0,...,a ^ k = 1 mod n和a ^ {(2 ^ i)k} = -1 mod n。 。 。 ,e − 1}。
您会看到'm'列中的所有值都不为1,而平方列中的任何值都不为14。因此它们都是见证人,因此> 50%是。
正在执行“ check-nontrivial-sqrt1”的代码在n = 3(mod 4)的特定情况下不相关,因为在这种情况下e = 1。
更新:
我刚刚意识到我们有很多证人的原因,但是我们并不总是从他们身上找到平方根:
米勒-拉宾证人的想法是找到一个意外的1 mod n的平方根。这并不总是我们真正发现的,因为质数n的前提n-1≡1 mod n对于复合n可能并不正确。
这是一张n = 15的a ^(n-1)(mod n)表
(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)实际上只有两次。