2007 年度「計算機基礎論3B」 2008-01-25

§31 modulo m での計算

(31.1) この節は数学の話である。 Z/mZ, Z/m, Zm などと書かれる環の演算について、 初めての人にもわかりやすい形で説明する。 くわしくは代数学の時間に習うであろう。

(31.2) 2 以上の整数 m をひとつ選び固定する。 二つの整数 a と b に対し、a-b が m で割り切れるとき、 すなわち a-b = mq となる整数 q が存在するとき、 「a と b は m を法として等しい」 「a と b は modulo m で等しい」 などと言い、 「a ≡ b (mod m) 」「a ≡ b (m) 」 などと書く。 mod m で考えていることが明らかな場合は単に 「a ≡ b」とだけ書くことも多いし、 さらに省略して「a = b」と書くこともある。

(31.3) 「modulo」は 原語(ラテン語)に忠実に読めば「モドゥロー」だろうが、 普通は「モドゥロ」「モデュロ」「モジュロ」などと読む。

(31.4) たとえば 「3 ≡ 8 (mod 5)」、 「28 ≡ 3 (mod 5)」、 「-2 ≡ 8 (mod 5)」など。

(31.5) この関係は同値関係である。すなわち、 「a ≡ a (mod m)」、 「a ≡ b (mod m) ならば b ≡ a (mod m)」、 「a ≡ b (mod m) かつ b ≡ c (mod m) ならば a ≡ c (mod m)」 が成り立つ。

(31.6) a ≡ a' (mod m) かつ b ≡ b' (mod m) ならば a+b ≡ a'+b' (mod m), a-b ≡ a'-b' (mod m), ab ≡ a'b' (mod m) が成り立つことは容易に確かめられる。

(31.7) 任意の整数 x に対し、 0 以上 m-1 以下の整数 y がただひとつ存在して x ≡ y (mod m) となる。

(31.8) よって、0, 1, 2, ..., m-1 だけを数だと思い、 その間に加法、減法、乗法を定義することができる。 たとえば 「3 + 5 = 8 ≡ 2 (mod 6)」、 「3 - 5 = -2 ≡ 4 (mod 6)」、 「3 × 5 = 15 ≡ 3 (mod 6)」など。 (つまり、普通に計算し、 結果が「0 以上 m-1 以下」という範囲をはずれたら、 その範囲に収まるよう m の整数倍を加減する。)

(31.9) #define M 6 などとし、 mod M での加法、減法、乗法の表(九九の表のようなもの) を出力するプログラムを書いてみると、理解が深まるかもしれない。

(31.10) 除法を考えよう。 a ≡ bx (mod m) が成り立つような x が、a を b で割った商である。 modulo 6 で考えるとき、3 を 2 で割ることはできない。 いかなる数 x についても 2 × x は偶数であり、 それと奇数である 3 とが modulo 6 で等しくなることはあり得ないからである。 modulo 5 で考えるなら、3 を 2 で割った商は存在する。 2 × 4 = 8 ≡ 3 (mod 5) であるから 4 が答えである。 (9 と答えてもよいが、ここでも答えは 0 以上 m-1 以下の整数の中から選ぶことにしよう。)

(31.11) m が素数のときを考えよう。 素数らしく p と書くことにすると、 modulo p で考えるとき、 任意の数に対し、その数を 1 以上 p-1 以下の任意の整数で割ることができる。 すなわち、 任意の整数 a と 1 以上 p-1 以下の任意の整数 b に対し、 ある整数 x が存在して a ≡ bx (mod p) を満たす。

(31.12) 証明: a - bx = pq を満たす整数 x と q が存在することを示せばよい。 移項して bx + pq = a とすれば、 b と p は互いに素だから、代数学の時間に習った定理から x と q の存在がわかる。

§32 課題2

(32.1) 適当な十進二桁の素数 p を一つ選び固定する。 任意の整数 a と 1 以上 p 未満の整数 b に対し modulo p で a を b で割った商を返す関数 int divmod(int a, int b) を書け。 すなわち、 積 bx が modulo p で a になるような整数 x を返す関数を書け。 x は 1 以上 p 未満に値をとるようにせよ。

(32.2) main() もつけて、 そのままコンパイルして動かすことのできるものを提出すること。 main() をどんなふうに書くかは各自の判断に任せる。

(32.3) 提出方法などは課題1に準ずる。 ただし件名は「kadai2」 (←全て半角文字、アルファベットは小文字、途中にスペースをいれない) とせよ。 締め切りは 2008 年 02 月 01 日(金)17 時 00 分。

(32.4) ヒント: 答えは 1 以上 p-1 以下の整数のうちに必ずあるわけだから、 順に調べてゆき、見つかったらそこでその値を return すればよい。 よって、return を置く位置は関数の最後ではない(かもしれない)。

(32.5) 素数 p は勝手に選んで、 レポート内に「私は素数 17 を選びました」 「modulo 17 で割り算をする関数を書きました」 のように書けばよい。 選んだ数が素数であることをプログラム内で確かめる必要はない。

(32.6) 答えが二つある場合があるかどうかは、各自考えること。 もしそういう場合があったとしても、そのうちの一つを返すように書けばよい。

(32.7) 商は存在すると仮定してプログラムを書いて構わない。 「もしも見つからなかった場合」のために if などを使う必要はない。

(32.8) 間違って 0 で割った場合のことは考えなくてよい。 (でも、呼び出したらどうなるか実験してみるのはよいことである。)

(32.9) ヒント:余りを求める演算子は % であった。 10 % 3 は 1 となる。

(32.10) このプリントで使っている「≡」の記号はテキストファイル内では使えない。 printf() で出力させる文章やレポートの中に使いたいなら、 「=」で代用することをすすめる。 (「」は確か機種依存文字だったので使わないほうがよいだろう。)

§33 アカウントは「今学期限り」かも知れません

(32.1) 今学期の初めに (1.5) で説明したように、 この授業で配布したアカウントは三月末日まで有効ですが、 有効期間をもう一年間延長してもらうことを願い出ています。

(32.2) 来学期の「計算数学1」では、 この授業のアカウントが延長されればそれを使いますし、 そうでなければ新たにアカウントを配布する予定です。 また、「計算数学1」で使ったアカウントは来年度後期の教職科目「総合演習」でも使います。

(32.3) 来年度の「計算数学1」「総合演習」をとる予定の人もとらない予定の人も、 この授業で配布したアカウントのパスワードは、今学期終了後も、 きちんと管理してください。 すなわち、 「授業期間が終わったからパスワードを書いた紙はもういらないや」 と言って人目につくところに捨てたりすることはしないでください。

(32.4) 自分のホームに置いてあるファイルをとっておきたい人は、 各自でなんとかしてください。 家のパソコンなどにメールアカウントを持っている人は、 メールに添付して送ってしまうのが最も簡単で安全です。 実行ファイル a.out は持って帰ってもほとんど意味がありません。念のため。


岩瀬順一