SICP 読み (11)

なかなか前に進まない。一歩進んで二歩下がった挙句に (以下略

Fermat テストについて (続)

  • ある二つの数を同一の数 n で割った時、同じ剰余を持てば、_n を法として合同_という
  • 数 a を n で割った剰余を_ n を法とした a の剰余_とか_ n を法とした a _という

上記を踏まえ、以下。

n を素数、a を n より小さい正の任意の整数とすると、a の n 乗は n を法として a と合同である。

となる、と。まだ意味分からんな。
n が素数だとしたら a の n 乗を n で割った剰余と a を n で割った剰余は等しい、という事か。それを踏まえて以下のコードを見るに

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

上記は、SICP によると

ある数のべき乗の別の数を法とした剰余を計算する手続き

とある。scheme のコードは目に慣れた、と思っていたんですが、上記コードは理解に時間がかかっております。頭弱いよう。

つづき

問題 1.25 にもあるんですが、何故に (expmod 3 5 5) が (remainder (* 3 3 3 3 3) 5) になってないんだろう。

置き換えモデルで試してみた。

(expmod 3 5 5)
(remainder (* 3 (expmod 3 4 5)) 5)
(remainder (* 3 (remainder (square (expmod 3 2 5)) 5)) 5)
(remainder (* 3 (remainder (square (remainder (square (expmod 3 1 5)) 5)) 5)) 5)
(remainder (* 3 (remainder (square (remainder (square (remainder (* 3 (expmod 3 0 5)) 5)) 5)) 5)) 5)
(remainder (* 3 (remainder (square (remainder (square (remainder (* 3 1) 5)) 5)) 5)) 5)
(remainder (* 3 (remainder (square (remainder (square (remainder 3 5)) 5)) 5)) 5)
(remainder (* 3 (remainder (square (remainder (square 3) 5)) 5)) 5)
(remainder (* 3 (remainder (square (remainder 9 5)) 5)) 5)
(remainder (* 3 (remainder (square 4) 5)) 5)
(remainder (* 3 (remainder 16 5)) 5)
(remainder (* 3 1) 5)
(remainder 3 5)
3

うーん。分かりにくいなぁ。たしかに書いてある通りの処理をしてはいるんですが、何故に_別の数を法とした剰余_を計算する手続きが必要なんでしょうか。

上記手続きを式にしてみるか。

;; 3 ^ 5 を 5 で割った剰余の取得
(expmod 3 5 5) 

;; 3 ^ 4 を 5 で割った剰余に 3 を掛けた値を 5 で割った剰余の取得
(remainder (* 3 (expmod 3 4 5)) 5)

ぬ。ってコトは (expmod 3 4 5) と (remainder (square (expmod 3 2 5)) 5) は同値になるのか。なんでだろ。
3 の二乗を 5 で割った剰余は 4。4 ^ 2 は 16 で 5 で割った剰余は 1 か。

((* 3 3 3 3 3) modulo 5) = ((* 3 ((* 3 3 3 3) modulo 5)) modulo 5)

((* 3 3 3 3) modulo 5) = ((square ((* 3 3) modulo 5)) modulo 5)

になるんか。ちなみに modulo 演算子 の左辺を比べてみると

(* 3 3 3 3 3) ;; => 243 
(* 3 (remainder (* 3 3 3 3) 5)) ;; => 3

両方ともに 5 で割った剰余は 3 (当たり前
あるいは

(* 3 3 3 3) ;; => 81
(square (remainder (* 3 3) 5)) ;; => 16

これも両方 5 で割った剰余は 1 (当たり前
もう少し見てみよう。

((* 3 3) modulo 5) = ((square (3 modulo 5)) modulo 5)

これは分かり易い。modulo 演算子の左辺は同一の値。

トレイスもかけてみた。

guile> (expmod2 3 5 5)
[expmod2 3 5 5]
|  [fast-expt 3 5]
|  |  [fast-expt 3 4]
|  |  |  [fast-expt 3 2]
|  |  |  |  [fast-expt 3 1]
|  |  |  |  |  [fast-expt 3 0]
|  |  |  |  |  1
|  |  |  |  3
|  |  |  9
|  |  81
|  243
3
3
guile> (expmod 3 5 5)
[expmod 3 5 5]
|  [expmod 3 4 5]
|  |  [expmod 3 2 5]
|  |  |  [expmod 3 1 5]
|  |  |  |  [expmod 3 0 5]
|  |  |  |  1
|  |  |  3
|  |  4
|  1
3
3

くりかえし、というか再帰呼び出しが一回多いな。戻り値の桁も少ない。ってか、この位の感想しかないあたり、痴呆気味だよ。

ただ、不思議なのは

(square (remainder (* 3 3) 5))

を 5 で割った剰余が

(* 3 3 3 3)

を 5 で割った剰余と同じ、な事です。何か法則みたいなナニがあるのか。

1.25 は答えに辿り着くまで、相当遠いな。

追記

微妙な記述を修正。しかしワケ分かんねぇ。