SICP 练习 1.28
https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-ZH-11.html#%_thm_1.28
费马测试的一种变体被称为 Miller-Rabin 测试(Miller 1976;Rabin 1980)。这从费马小定理的另一种形式开始,该定理指出如果 n 是质数并且 a 是任何小于 n 的正整数,则 a 的 (n - 1) 次幂等于 1 模 n。为了通过 Miller-Rabin 检验测试数字 n 的素数,我们选择一个随机数 a < n 并使用 expmod 过程将 a 提高到 (n - 1) 次幂模 n。然而,每当我们在 expmod 中执行平方步骤时,我们都会检查我们是否发现了“1 模 n 的非平凡平方根”,即一个不等于 1 或 n - 1 的数,其平方等于1 模数 可以证明,如果存在这样一个 1 的非平凡平方根,则 n 不是素数。如果 n 是一个非素数的奇数,那么,对于至少一半的数字 a < n,以这种方式计算 a^(n-1) 将揭示一个模数为 n 的非平凡平方根。(这就是为什么 Miller-Rabin 测试不能被愚弄的原因。)修改 expmod 过程以发出信号,如果它发现 1 的非平凡平方根,并使用它来实现 Miller-Rabin 测试,过程类似于 fermat-test。通过测试各种已知的素数和非素数来检查你的程序。提示:产生 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:我现在还手动计算了从 1 到 14的所有值的步骤(它总是通过, , , , , ,expmod(a, 14, 15)
递归),我确信只有并遇到一个非平凡的平方根 1。所以我倾向于认为 SICP 对此要么是错误的,要么是没有清楚地表达自己。exp = 14
exp = 7
exp = 6
exp = 3
exp = 2
exp = 1
exp = 0
a
a = 4
a = 11