その後、竹田津は教育BBSを威力偵察していたのだが、またあるメッセージに目が留まった。
NO.1414 プログラマ練習課題 |
---|
投稿者/ 社長@アルファ 投稿日/ 2001/08/09(Thu) 11:14:10 URL/ |
頭の体操です。
言語は、何を使っても良いがなるべくアセンブラでない方が良い。
取りあえずCにしておきましょう。
変数 a,b,c に何らかの数値を代入します。
a = 乱数;
b = 乱数;
c = 乱数;
この先が問題。
変数 max にa,b,cの内の最大値を入れ、
変数 min にa,b,cの内の最小値を入れ、
変数 mid に最大でも最小でも無かった値を入れなさい。
問題は、以上。(注意、a,b,c同じ場合は、max,min,midは同じにな
ります。)
課題は、演算または、代入が発生する処理は、いくつあれば書けま
すか?
例
max = a; /* これ一つで 1と数える */
if(a > b) { a = c } /* これは、2と数える*/
max = a+ c +d; /* これも1と数える */
最初は、数だけ答えてください。
皆の答えが出そろった位にもう一度、ソースを答えて貰う2段形式
にして下さい。
これだと、コンピューター無くても紙と鉛筆で出来ますよね。
時間の無い人でも考えることが出来るでしょう。
こんな問題、プログラマの竹田津にとって見れば朝飯前の課題である。ただし、オーバーフローには気をつけないといけないから、初心者ならひっかかりやすい問題ではある。
そして「正解」と書かれたメッセージは次の通り。
NO.1588 プログラマ練習課題について |
---|
投稿者/ 社長@アルファ 投稿日/ 2001/08/16(Thu) 11:00:22 URL/ |
一つの命題に対して、いくつもの解法手順が存在します。
まず、それを知って欲しい。
今回の命題は、如何に簡単に短くバグを生まない手法かが問われています。
私が書いたプログラムは、
max = a;
if (b>max) max =b;
if (c>max) max =c;
min = a;
if (b<min) min =b;
if (c<min) min =c;
mid = a+b+c-max-min;
でした。
else も else ifも使わずにこれで、15です。
アセンブラにしても簡単に変換出来るでしょう。
midの求め方が変則的ですが、最初のルールでは、11となります。
皆さんの回答にもっと少ない回答がありますが、カウントの仕方
によっても異なりますのでここは、15カウント以下では及第点と
しておきましょう。
他人のプログラムの手法を見る事は、非常に勉強になりますので
多くのプログラムに接してテクニックやノウハウを是非学んで頂
きたいと思います。
小さいプログラムでしっかり動く事。どう見てもバグを生まない
構造を基本にして下さい。
単純なアルゴリズムほど思いつくのに時間がかかったりしますが
いつもどうしたら短くなるだろうとか、簡単に解決する方法はな
いかなぁとか考える事です。常に考えているとふっと思いつくも
のです。
今回、こんなに簡単な課題に対し、答えを寄せなかった人は、あ
まりに簡単すぎてやらなかったのか、それとも難しくてやらなか
ったのかどちらなのでしょう。
また、課題2に関して
プログラムは、ちょっとした事でものすごく速いプログラムにな
ります。アルゴリズムは、同じでも無駄をなくせばめちゃくちゃ
に速くする事が出来る事を学んで欲しい。また、それを常に考え
心がけるようにしましょう。
「おいおい、噴飯物だぜ」
プログラマの仕事は「いかにオーバーフローを起こさないか」との戦いといっても過言ではない。そのためにプログラマは無意味な四則演算を極力嫌う。もし演算しなければならない時は、細心の注意を払う。
そこで竹田津は次のようなメッセージを書き込んでみた。
NO.1601 Re[2]: プログラマ練習課題について |
---|
投稿者/ taked2 投稿日/ 2001/08/17(Fri) 03:43:34 URL/ |
質問
> mid = a+b+c-max-min;
においてオーバーフロー、アンダーフローはどう解決するのでしょう?
それに対する回答は次の通り。
NO.1602 Re[3]: プログラマ練習課題について |
---|
投稿者/ 社長@アルファ 投稿日/ 2001/08/17(Fri) 08:25:27 URL/ |
> 質問
>
>>mid = a+b+c-max-min;
>
> においてオーバーフロー、アンダーフローはどう解決するのでしょう?
解決出来ません。
最初にこの問題を作ったのが、20年ほど前で当時BASICのフローティング
演算をさせていたのでほぼ問題とならなかったし、INPUT文で入力させて
いました。
さらに、midは、おまけでつけたもので回答の一つと言う事です。
皆さんにこの問題の主旨が分かって頂けてアルゴリズムについて一考され
ればそれで十分な成果を果たしていると感じています。
プログラマが別の手法にて私の回答より短いのを書いていましたが、
同様のプログラムがどなたかの回答に上がっていましたのであえて書く事
もないでしょう。
付け加えておけば、ゲームにおいて未知の数が与えられることは、殆ど
有りません(企画や仕様により範囲が限定されている)が、通常のプロ
グラムでは、オーバーフローなどは、エラー処理でユーザーに通知する
のが良いでしょう。
「まあ、初級は分かっているか」
竹田津は回答として次のメッセージを書き込んだ。
NO.1603 Re[4]: プログラマ練習課題について |
---|
投稿者/ taked2 投稿日/ 2001/08/17(Fri) 08:33:42 URL/ |
今回の主旨は分かっているつもりです。
> 付け加えておけば、ゲームにおいて未知の数が与えられることは、殆ど
> 有りません(企画や仕様により範囲が限定されている)が、通常のプロ
> グラムでは、オーバーフローなどは、エラー処理でユーザーに通知する
> のが良いでしょう。
オーバーフロー、アンダーフローを発生させないのはプログラマの責任だと思っています。可能性があるならキャストするなり、代案を考えた方がいい、と。
この問題はいままで何度も痛い目にあってきたので、おせっかいながら書かせていただきました。
そして「自分の正解」として次のメッセージを書き込んだ。
NO.1599 Re[2]: プログラマ練習課題 |
---|
投稿者/ taked2 投稿日/ 2001/08/17(Fri) 02:41:26 URL/ |
/* 最小値の判定 */
min = a;
if (b < min) { min = b; }
if (c < min) { min = c; }
/* 最大値の判定 */
max = a;
if (b > max) { max = b; }
if (c > max) { max = c; }
/* 最小でも最大でもない値の判定 */
mid = a;
if ((min < b) && (b < max)) { mid = b; }
if ((min < c) && (c < max)) { mid = c; }
なるほど、みなさんの解答を見ていると演算を使う人が多いんですね。でもオーバーフロー、アンダーフローの問題はどう解決するのでしょう?
初期値が乱数で、初期値の範囲がその型で表現できる全ての範囲であれば、2値を合計した時、オーバーフロー、アンダーフローが発生する確率は50%ですね(浮動小数点型の型を除く)。
一般の数学とコンピュータプログラムの最も大きな違いはここにあると思うんですが。「演算する必要がない時(演算しなくても判定だけで十分な時)は演算をしない」というのはセオリーだと思っています。 いかに簡単に書けるように見えるプログラムでも、動かないプログラムを書いたんじゃ意味ないですよね。素人なら仕方ありませんが、そんなのは「プロ」の書くプログラムとはいえないでしょう。
おまけ
あと最後を
/* 最小でも最大でもない値の判定 */
mid = a;
if (min < b) { if (b < max) { mid = b; }}
if (min < c) { if (c < max) { mid = c; }}
って書きゃ17になりますけど、アセンブルコードまで考えたら大差ないですしね。大体こんな風に書いたら普通は殴られますね。
50%の確率でオーバーフローが発生する、言い換えれば50%の確率でプログラムが動かないのであれば、そんなものは欠陥品というしかない。プログラマが四則演算を嫌う最大の理由は、四則演算を使えば使うほど、プログラムが動かなくなる可能性が大きくなるからだ。無駄な四則演算はしない、というのは、プログラマの習性といってもいい。
「まあ、プログラマのレベルはこのくらいか」
プログラムは戦場になりそうにないので、以後、通常偵察に切り替えた。
(*注意* 登場する人物、団体等は、全て架空のものです)