2013年11月10日日曜日

C/C++ 階乗の計算

コンピュータと言えば計算が得意です。ですから計算のプログラムを作ってみます。計算は階乗(factorial)の計算で、nという数字を与えた時に、1×2×3×4×・・・・×(n-1)×nという1からnまでを掛けた値になる計算です。なお0の階乗は1となります。

まずはどのように動くかという仕様を決めます。これだけのプログラムでも色々と考える必要があります。
  1. コマンドライン引数で階乗の数値を入力する。
  2. コマンドライン引数で入力した数値から階乗を計算する。
  3. 計算した結果をコンソールに表示する。
  4. 引数では数値を入力する。数値以外は0と見なす。
  5. 数値がマイナスの場合はエラーを表示し、2を返す。
  6. 小数点がついていた場合は、小数点以下を無視する。
  7. 引数の数が1つでない場合はエラーを表示し、1を返す。
  8. 値のオーバーフローは考慮しない。
上記のように動くソースコードを書きます。fact.cとします。


コンパイルし、実行を行うと以下のようになります。



ソースコードの解説を簡単にします。

ソース説明
main(int argc,  char *argv[])今回はmain()関数にint argc, char *argv[]という2つの引数がついています。argcは整数(int)で、引数の数を表します。argvは引数の文字列の配列を意味します。*や[]の意味はまた機会があれば説明します。とりあえずargv[1]などが一つ目の引数の文字列と解釈してください。
int value, fact, i;valueと、factと、iという名前の整数のデータ領域を作成しています。
if (argc != 2) {...}引数の数(argc)のチェックを行っています。引数の数にはコマンド自身の数も含まれるので引数が1つのときには2となります。!=2はargcが2で無いかどうかという計算で、その結果により、{...}内の処理を行います。

value = atoi(argv[1]);
引数の文字列argv[1]を整数値に変換して、valueに代入しています。文字列のままでは計算ができないためです。atoi()というのは文字列を整数値に変換するライブラリ関数です。stdlib.hに入っているのでstdlib.hを#includeしています。
if (value < 0) {...}引数を整数値に変換したvalueが0より小さい場合に{...}の処理をします。
fact = 1;factというデータ領域に1を代入します。
for (i = 1; i <= value; i++) {...}繰り返し処理を行い、階乗を求めています。(1)iのデータ領域に1を代入します。(2)iがvalue以下の値か調べ、iがvalue以下の値であれば、{...}の処理を実行し、そうでなければ{...}の次の行の処理に移ります。(3){...}内の処理が終わったらi++を実行します。i++はiの値をi = i+1と同じ意味でiの値に1つ値を足します。
fact = fact * i;アスタリスク(*)は掛け算の意味です。iが1つずつ加算するのを繰り返すことで、階乗を計算します。
printf("factorial = %d¥n", fact);
階乗の値を出力します。printf()で表示する文字列の指定内のパーセント(%)には意味があり、%dは整数(int)の表示を行うことを意味します。文字列の後ろの引数に%dに表示するデータを列挙します。

複雑になりましたが、それは今回のプログラムがユーザーからのコマンドラインからの入力が増えたことが原因です。これでもオーバーフローを考慮しないなど、処理が少なくなるようにサボっています(17の階乗でなるはずの無いマイナス値となっているのはオーバーフローのためです)。

通常の場合、プログラムはユーザーの入力に対し、何かの処理を行います。ユーザーの入力は何があるか分からないので、入力を制限する処理を入れたり、どのような入力でもチェックによりエラーを返すなどの処理を入れなくてはいけません。そうしないと 想定外の問題が起こることになります。

この想定外の問題をいかにして少なくすることができるかが、プログラマの腕の見せ所の1つです。

それと、今回はCPUの処理(演算と制御)の部分とメモリ(データ領域の作成)の部分がHello Worldに比べて多く増えています。それらについてはまた次回。

0 件のコメント:

コメントを投稿