SICP Упражнение 1.28
https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-11.html#%_thm_1.28
Один вариант теста Ферма, который нельзя обмануть
называется тестом Миллера-Рабина (Miller 1976; Rabin 1980). Это начинается
из альтернативной формы маленькой теоремы Ферма, которая утверждает, что
если n простое число и a любое положительное целое число меньше n, то
возведенное в (n - 1) -й степени соответствует 1 по модулю n. Тестировать
простоту числа n по критерию Миллера-Рабина, мы выбираем случайное
число a если n нечетное число, которое не является простым, то,
хотя бы для половины чисел a (Вот почему
Тест Миллера-Рабина не может быть одурачен.) Измените процедуру expmod на
сигнал, если он обнаруживает нетривиальный квадратный корень из 1, и использовать это для
выполнить тест Миллера-Рабина с помощью процедуры, аналогичной
Fermat-тест. Проверьте вашу процедуру, протестировав различные известные простые числа и
не являющиеся простые числа. Подсказка: один из удобных способов сделать сигнал 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
, что намного меньше, чем минимум, как и ожидалось.
Я неправильно понимаю утверждение? Я полный идиот? Код неправильный? 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
, exp = 2
, exp = 1
, exp = 0
), для всех значений a
от 1 до 14, и я уверен, что только a = 4
и a = 11
встречают нетривиальный квадратный корень из 1. Поэтому я склонен думать, что SICP либо ошибается в этом или не выражает себя четко.