反復処理の基本形| for ( A ; B ; D ) C; Aは空か文. 反復される前に一度だけ実行される. Bは空か条件式. Bが空がBが真な条件式ならば反復が継続される. Cは空か文. 反復の各段階で実行される文 Dは空か文. 次の反復の段階に移るときに実行される文 |
![]() |
(1) F1=1, F2=1, Fi=Fi-1+Fi-2 (i ≥ 2)
の 9 頁目を計算してみましょう. Fi の値は直前の二つの頁 Fi-1 と Fi-2 の値さえ覚えていれば計算できます. Fi を計算するプログラムは, Fi-1 の値を格納する変数 fibonacci と Fi-2 の値を格納する変数 old_fibonacci があれば良く, 変数 fibonacci と old_fibonacci を同時に, fibonacci + old_fibonacci と fibonacci に更新します. このとき, まず F3 の値を計算するために式(1)を1回使い, Fn を計算するには式(1)を合計 n-2 回使います. つまりFn を計算するには変数 fibonacci と old_fibonacci を合計 n-2 回更新します.
/* Fibonacci.c フィボナッチ列の第 9 項目をプリントするプログラム */ main() { int n ; int fibonacci ; int old_fibonacci; int xx; old_fibonacci = 1; fibonacci = 1; for (n=3; n<=9; n++){ xx = fibonacci; /* 次の行は 変数fibonacciに格納されている値を更新するので, その前に fibonacci に既に格納されている値を変数 xx に保存する */ fibonacci = fibonacci + old_fibonacci; old_fibonacci = xx; } printf("%d\n", fibonacci); return 0; }
演習3-1. フィボナッチ数列 Fn (n ≥ 1) の一般項の数式を与えよ.
この例では, 変数nを使って意図的に 「printf("%d\n", n); n=n*3 ; 」という全く同じパターンを作っていることに注目して下さい. そうすると, その部分を「 printf("%d\n", n) ; n=n*3; を9回反復せよ 」と記述できれば便利, と誰でも思います. C言語では, それをfor文を使って, 以下のように記述します:プログラムの流れを右に図示しました. プログラムを「読む」際に, 変数の状態変化も頭の中で想像してみると良い. 初期化しないと,その変数(メモリー)の中身に何が入っているのか,一般には不定ですので, 値を設定していない変数に自分の都合のよい値(例えば0)が入っていると仮定してはいけません.
/* simple_power.c 3の0乗から8乗までプリントするプログラム */ main() { int n ; n=1 ; /* <== 注目:まず最初に n を 1 に初期化 */ printf("%d\n", n) ; n=n*3 ; /* n の値に3をかけたもので n の値を更新 */ printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; n=n*3 ; printf("%d\n", n) ; return 0 ; }
/*
simple_beki.c
forによる反復(ループ)により
3の0乗から8乗までプリントするプログラム
*/
main() {
int n;
int i;
n=1;
for (i=0; i<9 ; i=i+1) {
printf("%d\n", n) ;
n=n*3;
}
return (0) ;
}
|
![]() |
| 27 の 7乗 | 10460353203 |
| 1ワードが32ビットである場合, int型変数が格納できる最大の整数 = 2 の 31乗 -1 | 2147483647 |
(xy) % m = ((x % m) * (y % m)) % m
証明は z % m ≡ z (mod m) であることと, 合同式の性質 「a ≡ b (mod m) かつ c ≡ d (mod m)ならば ac ≡ bd (mod m)」を用います.
冪乗を計算するための時間について -- 冪乗法例題3-5. p = 11 とする. 次をプログラムを書け.
| /* kotae.c 例題3-5 の答え */ main() { int n; int i; int x; int p; p=11; printf("11-1以下の正整数 x を入力してください\n"); scanf("%d", &x); n=1; for (i=0; i<p-1; i=i+1) { printf("%d\n", n) ; n=(n*x) %p; /* n が大きくならないようにするために 乗算をする毎に剰余を取る */ } return (0) ; } |
Fermat の小定理. p が素数ならば x の p-1 乗を p で割った余りは1(x=1,...,p-1)
が成立します. RSA暗号でも使われています. その簡単な証明はいくつかります.素数 p の剰余系は必ず原始根 g を持ちます(教科書28節). すなわち
どんな素数 p に対してp 未満の適当な正整数 g があり,
p未満のどんな正整数 a も g の適当な冪と, 法 p で合同.
Y = r0 + r1m0 + r2m0m1 + r3m0m1m2 + ....+ rD-1m0m1...mD-2
を満すものの中のひとつ.
原始根・暗号関係の参考文献