スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
以後の更新内容の改善のために、是非ともご評価のほどよろしくお願いします!→

【C言語】階乗を計算する関数(訂正版)

このサイトに掲載している以下の記事...
C言語で階乗計算をする。
PHP練習[5]:階乗計算
...の中に、記述ミスがありました。(お詫び申し上げます...m(__;)m)

ご存知の通り「nの階乗」というのは、1からnまでの自然数を掛け合わせたものです。
確かに、下で提示する関数ではその処理がおこなえるように見えますし、実際に動作もしています。

// 多くの場合、階乗計算をおこなうことができる関数
int fact(int num){
    int i;
    if(num == 1){
        return 1;
    } else {
        i = num * fact(num - 1);
        return i;
    }
}

しかし、この関数は完全ではありません。
この関数の引数に0(ゼロ)や負数(0より低い数)が入ると危険です。

目で追ってみるとわかると思います。
0以下の数値を引数にすると、関数内で無限ループ状態になってしまいます。
(GCCでコンパイルして実行した場合、Segmentation fault(というエラー)が出ました。)



そもそも、0!(ゼロの階乗)は定義上では「1」になります。
これはお約束(?)なので、特別に定義してやる必要があります。

また、負数が指定された場合は、一般に階乗計算をおこなうことができません。
なので、ここでは適当に「-1」を返すようにします。
(単なるエラーを示すための数値なので、階乗計算であり得ない数値ならなんでもOKです。例えば「0」でもOK。)
その改善を施したのが以下の関数です。

// 厳密に階乗計算をおこなう関数
int fact(int num){
    int i;
    if(num < 0){
        return -1;
    } else if(num == 0){
        return 1;
    } else if(num == 1){
        return 1;
    } else {
        i = num * fact(num - 1);
        return i;
    }
}


この関数はちゃんと階乗計算をおこなってくれるはずです。

...しかし!! よく見てください。

この関数は再帰呼び出しをおこないます。
すると、入力値チェック(「num < 0」とか「num == 0」の部分)が毎回計算されるわけです。
(一度、階乗計算の処理に入れば、入力値のチェックは必要ないのです。。。)

すなわち、無駄な処理をしてしまう...ということです。
これは、いただけない...(笑)


それを改善すべく、以下のようにします。

// 階乗処理そのものをおこなう関数
int fact_do(int num){
    int i;
    if(num == 1){
        return 1;
    } else {
        i = num * fact_do(num - 1);
        return i;
    }
}

// 入力値をチェックして、正しい入力であればfact_do()を呼び出す関数
int fact(int num){
    int i;
    if(num < 0){
        return -1;
    } else if(num == 0){
        return 1;
    } else {
        i = fact_do(num);
        return i;
    }
}

階乗の計算処理そのものをおこなうのは関数fact_do()ですが、
実際に私たちが使用するときは、関数fact()を呼び出すだけです。

このように書くと、入力値のチェックは1回しかおこなわれません。
無駄なことをしない=効率が良い...ということですね!(きっとメモリを食いますが^^;)



本質的には上の書き方で問題ないですが、ちょっと長々しくて嫌ですよね?^^;;


なので、もう少しスマートに(ってかこざかしく...)書いてみましょう。

// 階乗処理そのものをおこなう関数
int fact_do(int num){
    return ((num == 1) ? 1 : (num * fact_do(num - 1)));
}

// 入力値をチェックして、正しい入力であればfact_do()を呼び出す関数
int fact(int num){
    if(num < 0){
        return -1;
    } else {
        return ((num == 0) ? 1 : fact_do(num));
    }
}

このように条件演算子(「条件式 ? 式1 : 式2」の形)を使うと少ない行で書けてしまいます。

この書き方には賛否両論あるみたいなので、使うか使わないかは自分次第...ですっ!^^;
スポンサーサイト
以後の更新内容の改善のために、是非ともご評価のほどよろしくお願いします!→
カテゴリー
ようこそ!
Author: Torasuke
Profile: 地元大学の情報系学部に息をひそめる二回生。
   SA SW


ブログ内検索
最近のコメント
オススメ
京都の大学生のラボブログ
Python,Java,Objective-C,GAE,Macなど
Python独習中の大学生のブログ


ltzz.info
ここの管理者さんには謁見済み!(えっ

 Use OpenOffice.org
無補償でも良いなら、MSOfficeよりOpenOfficeで十分です。

Mozilla Firefox ブラウザ無料ダウンロード
当サイトは、Firefoxというブラウザで動作確認しています。私は以前、IE派でしたが、一度乗り換えて慣れてしまうと、Firefoxのほうが便利だということを実感しました。

是非よろしくお願いします。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。