ループ - みる会図書館


検索対象: ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法
35件見つかりました。

1. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 9 回 プログラミングのイディオム ( 前編 ) 「ダメだとしたら ? 」 「どうしてもっていうことなら・・・これでどうでしよう ? 」 マリスト 11 byte 型のダウンカウントによる正しい n 回繰り返しその 3 for(byte i = n ー 1 戸 > 0 冫 do—something(i); d0—something(O); 「ずいぶんまわりくどくないかな ? 」 「これは仕方ないと思います。なせなら、 n 回まわるループを書くとき、ループ変数 i を O から n - 1 になるまで 1 ずつ加算します。そうして i が n になったときにループを抜 けます。すなわち、ループ内でループ変数を O から n - 1 まで変化させるなら、 i は O から n までの値を表現できる型でないといけないのです」 v 図 1 ループ変数 i が取りうる値の範囲 0 「図 1 の塗りつぶし部分は、 i がループ内で取りうる値です。 " ↓ " は、ループを脱出す るために i が取らなければならない値です。同様に、ループ内でループ変数 i を n - 1 か ら O にダウンカウントする場合、 i は n-l から - 1 までを表現できる型でなければなら ないのです ( 図 2 ) 。 もし、 i を無符号型にしたいなら、図 3 のように、ループを『ループ内で i が n - 1 から 1 までをとるループ』 ( これは i が n - 1 から O までを表現できる型であれば実現できる ) と『 1 回のループ』に分解してやる必要があるからです」 167

2. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 9 回プログラミングのイディオム ( 前編 ) 「 fo 「は、初回のループに先立ちループ条件である fi!=O 』を評価してしまうので、 一度も do ー something ( ) を実行することなく、このループを抜けてしまいます」 「うん ! そうね ! 」 プログラミングのイティオム 3 「ループ変数が iterator の場合のループ」の巻 「ところでケンイチ君は、ループ変数が ite 「 at0 「の場合はどうやって書いてるかな ? 」 「たとえは std : : vecto 「の場合ですと、次のような形になりますね」 マリスト 17 std::vector に対するループ typedef std::vector く int> VEC; VEC v; for(VEC::iterator it=v. begin();it!=v. end(); + + it) dO something(); ひなた先生が嬉しそうにしていた。もう、ひなた先生のご機嫌はなおったのかもしれな いとケンイチは思った。 「 wh ⅱ e では書かないの ? 」 「書くこともあります。 w e で書くとこんな感じですかね」 マリスト 18 wh ⅱ e によるループ VEC::iterator it=v. begin(); wh i [ e ( i t ! =v . end ( ) ) { dO something(); 十十冫 「この場合、変数 it のスコープがループ外にまで出ているのはデメリットだと思いま す。また、 + + it がループことに必ず行われることが保証できませんね。 たとえば、 do something() の代わりに『 if (some-condition()) continue; 』の ように書いてあったとしたら、『 + + it 』が実行されずにループが回り続けます。こ れを利用してコードを書くこともなくはないですが、ループとしては、少しわかり にくい制御構造をしていると思います。そのへんは流儀の問題でしようけど」 171

3. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 10 回プログラミングのイディオム ( 後編 ) 「左辺は ( A Ⅱ B) と (A & & B ) の否定形ですから、これらの否定がとりたくなった ときに、この法則を使うと良いと思います」 「ケニチ君は、一体、いつ、そんな否定がとりたくなるんだ ? 」 「ええと・・・」 ケンイチは困った。否定がとりたくなる状況というのはどういう状況なのだ ? 「ケニチ君。たとえば、あるアルゴリズムを実装するのにループ構造が必要だと気 付いたとする。そのとき、まずは wh ⅱ e ( t 「 ue ) とタイプしないだろうか ? 」 「タイプすることがありますね。そのあと、ループの脱出条件を書きます。たとえ ば、リスト 1 のようなプログラムになります」 v リスト 1 ループ構造を含むプログラム w h i [ e ( t rue ) { do—somethingl(); if ( 条件 ) break; d0—something2(); 「うん。そのとき書く条件は、ループ脱出条件だ。人間の思考として、ループが破綻 するときの条件、すなわち、ループ脱出条件を考えるほうが直観的だ。しかし、 fo 「 も wh ⅱ e もそうはなっていないよな ? 」 「あっ ! そうですね ! fo 「も、 wh ⅱ e もループを " 抜けない " ための条件であって、 ループ脱出条件ではないですね ! ということは、ループ脱出条件が思い付いた場 合、それの否定形が必要になる。 たとえば、「 (A & & B) 」がループ脱出条件だとすれば、ループするための条件は、 この否定形である「 !(A & & B) 」です。ここで、ド・モルガン則が使えて、「 !A Ⅱ 旧」と単純化される。つまり、早井先輩は、そういう風にド・モルガン則を活用し ろと言いたいわけですね ? 」 ーん ! ! 誰がそんなことを言うか ! ! こら ! ! 」 「ば、、馬鹿も一 183

4. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 デバッグが 2 , 、 , ーくなるテクニック マ図 2 ループ変数 i がとりうる値の範囲 ( ダウンカウント ) ひなた先生が教える v 図 3 n -1 から 1 までをとるループ チリ 「さっすが一、ケンイチ君 ! すこいすこい ! 」 2 0 0 0 1 168 do—something(); for(int i=a;i く =b; + + i) v リスト 12 a から b までをとる for ループ 「お安い御用で」 「それじゃあ、ループ変数が a から b までをとる fo 「ループを書いてみて ? 」 0 「ループ変数が a から b までをとる for ループ」の巻 プログラミングのイティオム 2 「言葉の意味はよくわからないけど、とにかくすごい ! 」 0 「いやあ、これしきのこと、風の前の塵に同じですよ。わはははは」 0

5. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 9 回 プログラミングのイディオム ( 前編 ) マリスト 6 ダウンカウントによる n 回繰り返し for(int i=n;i>O; do_something(i); 「ループ変数をダウンカウントしてるんですね。このプログラム、一目しただけで は n 回のループだとはわかりにくいです。ループ条件が i > O となっていますが、書き 慣れていないとここを間違えて i > = O と書いたりしそうです。あるいは、 i>=O と書 いてあったりしても、それが誤りであることに気付かないかも知れないです」 「どうすれば、 i > O と i > = O を間違えずに済むかしら ? 」 「境界テストを頭の中でしてやると良いと思います。具体的には、 n が O と 1 のとき に正しくループするかどうかを考えるのです。 n が O だと O 回ループ、すなわち、ル ープせずに fo 「を抜けなければなりません。 fo 「の条件式が fi>=O 』だと、 1 回ルー プしてしまうので、誤りだとわかります。 また、同様に、 n が 1 だと 1 回のループ、すなわち、 1 回だけ do_something を実 行して抜ける。このことを頭のなかで確認してやります」 「なるほど。じゃあ、リスト 1 のようなループでは、そういう確認を頭の中ではしな いの ? 」 「しないですね。ああいうのは、見慣れているのでそこまで確認しなくとも n 回まわ るループであることはわかります。熟練したプログラマにとっては、 i の取りうる値す ら意識にのほってないと思いますよ。きっと、バターンとして認識していますから」 いちもく . 「うんうん」 「あと 1 つ気付いたのですが、後者のループは、 i が n から 1 までのカウントになって います。冒頭に出てきたループ ( O から n - 1 までのカウント ) と対称にしようと思 うと i は、 n-l から O までのカウントにしないといけないと思います。つまり、こう です」 ▽リスト 7 ダウンカウントによる n 回繰り返し for(int i = n ー 1 戸 > = 0 ーー i ) do—something(); 165

6. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 9 回プログラミングのイディオム ( 前編 ) 「 1 0 の部分が n に置き換わるだけですね」 for(int i = 0 冫 i く n 冫 + + i ) d0 something(); 「このとき、ループ変数 i の取りうる値は ? 」 「ループの中では、 i は O から n - 1 ですね。で、ループを抜けるとき i が n になる ? 」 「うん、正解 ! 」 「でもふだんあんまりそういうの意識しないですね。もう、 n 回まわるループがそう だと思ってるので」 「うん、そうよね」 「そもそも、 i が O から n - 1 までで合計 n 回まわっているのですけれど、それがバッと 出てこないと思うんです。最初、この表現を見たときは、『あれ ? n - 1 回しか回って ないんじゃないの ? 』とか不安になりました」 「そのときは、どうやって n 回まわるループであることを確かめたの ? 」 「 n に小さな数字を入れて成り立つかどうかを試してみたことを覚えています。 たとえば n に 1 を入れて考えると『 i が O から n - 1 まで』っていうのは『 i が O から O ま で』っていう意味になって、ああ、ループ内では i は O を取って、 1 回は実行されて いるんだな、とわかります。 n に 2 を入れて考えると『 i が O から n - 1 まで』っていうのは『 i が O から 1 まで』っていう 意味になって、ループ内では i が O と 1 を取って、 2 回まわるんだなってわかります」 「うんうん。小さな数字を入れて試してみるのは良い方法ね ! ところで、 fi<n 』と いうのは『 i!=n 』ではダメなの ? 「 n 回まわるループにおいてはその 2 つの差異はありませんが、 '<' が 1 文字なのに 対して " ! = " は 2 文字ありますから文字のタイプ量で劣っています。また、『 + + i 』 が『 i + = 2 』のようになった場合に、 fi!=n 』だと正常にループが終了しなくなりま 163

7. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 9 回 プログラミングのイディオム ( 前編 ) : 「うん、正解 ! 」 「でも、あまり見かけない書き方ですね」 「 C / C + + だとそうかもね。 BAS 旧だと、 TFOR I=A TO B 』だとか、 FORTRAN だ と fDO I=A,B 』だとか、なじみのものなのだけれど」 「なるほど・・・」 ケンイチは、言語ごとに用意された構文がプログラマの思考に与える影響について考え た。意外と、プログラマの思考は、プログラミング言語により制約を受けているのではな いかと思った。 「ところで、ループ変数の型を byte にしておいて、ループ変数が O から 255 までを 取るループって書けないかな ? 」 「それはちょっと難しいかも・・・」 マリスト 13 byte 型のルーフ嗄数による 256 回のループ for(byte i = 0 戸く 256 + + i ) do_something(); 「リスト 1 3 は一見、何のことはないループですが、実際にはこのループから脱出で きません。 256 という数字が byte 型の範囲外 (byte 型のとりうる値の範囲は O か ら 255 まで ) だから、 i が 256 という数字を取れないからです ( 図 4 ) 」 マ図 4 ループを抜けるためには i が 256 を取れる必要がある 0 254 255 256 169

8. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 , 2 らも倍 1 をくなるテクニック テパックが 「ループ変数の型を byte にしたままループ変数が O から 255 までを取るループを書 くのはどうやっても無理 ? 」 「えーと・・・ fo 「のままでは無理ですけれど・・・こうすれば書けます」 ▽リスト 14 ルーフ。変数が byte 型の 256 回ループ byte i = 0 do { d0 something(); } wh i [ e ( i ! = 0 ) 冫 ひなた先生か教える 「 i が p a 「 ound 注して O になるのをチェックしているのね ? 」 「ええ、そうです」 「 i が p a 「 ound する事実を利用しない場合はどう書けるかな ? 」 「その場合は・・・こうすれは書けますね」 v リスト 15 ルーフ嗄数が byte 型の 256 回ループ 2 byte i = 0 冫 wh i [ e ( t rue ) { do—something(); if ( i = = 255 ) break; 「この 2 つはどうして fo 「では書き換えできないのかな ? 」 「リスト 1 5 のものは、『 if ( i = = 255 ) 』というループ条件のチェックのあとに『 + + i 』 を行っています。 fo 「では、このループ終了のチェックとインクリメントの順番が逆 です。またリスト 1 4 は、 fo 「で書こうとすると、次のようになりますが・・ v リスト 1 6 for で書けるのか ? for(byte i = 0 冫 i ! = 0 + + i ) do—something(); 注 byte 型の取りうる最大値である 255 からインクリメントすると " 周回 " して byte 型の取りうる最小値である 0 になること 170

9. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 テ / ーッグが = 電ー - ーー丿くなるテクニック 「ケンイチ君、冴えてる ! 」 「でヘへへ。これくらい、氷山の一角ですよ。だはははは」 「う、うん。ケンイチ君の言ってる日本語の意味はよくわからないけど、ともかく すこいよね ! ところで、『 it!=v. end() 』の " ! = " は '<' ではダメなの ? 」 「あー、そう言われてみれば、さっきは、 " ! = " は '<' より劣るって話でしたね。 どうして今度は '<' でなく " ! = " なんだろう・・・考えたことなかったな」 ひなた先生か教える 「あっ ! そもそも ite 「 ato 「はひとつずつ要素を辿っていくためのもので、順序比較は 普通できないのではないですか ? だから " ! = " で書くしかないと。このループを図 示すると、こうなりますね」 マ図 5 iterator を用いたループ 0 v. begin( ) v. end( ) - 1 v. end( ) 「図 5 の黒い部分が、ループ内で it が取りうる値です。すなわち、ループ内では it は v. end ( ) という値は決して取りません」 「もし、 v. end ( ) が v の最後の要素を指す設計になっていた場合は、このループはど う書けば良いのかな ? 」 「図としては次のようになります」 172

10. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 テパックが 2 りつ倍貰もくなるテクニック ひなた先生が教える 「これはビックリ ! ケンイチ君、するどい ! でも、これがループ変数が byte 型 ( # unsigned cha 「型 ) であった場合はどうかな ? 」 「ひなた先生、いつにもまして意地悪ですね」 「もう。意地悪してないってば」 ひなた先生がちょっとすねて見せた。すねた顔のひなた先生も可愛い。 「リスト 7 のループの場合、 i は最終的に - 1 になってこのループを脱出することにな りますが、そのためには i の変数の型が符号型でなくてはなりません。これが byte 型のような無符号型であった場合 ( リスト 8 ) 、このループから永久に脱出できませ んね・・・」 マリスト 8 byte 型のダウンカウントによる n 回繰り返し ( 誤り ) for(byte i = n ー 1 戸 > = 0 do—something(); 「そうね ! じゃ byte 型に対してダウンカウントで正常にループから脱出するために は ? 」 「ええと、その場合ですと、こう書くしかないでしようね。リスト 9 の場合、 i を n か ら 1 までダウンカウントします」 マリスト 9 byte 型のダウンカウントによる正しい n 回繰り返し for(byte i=n;i>O;——i ) do—something(); 「 i を n - 1 から O でダウンカウントするようには書けないかな ? たとえば、 do something(i) のようにこのループカウンタ自体を使いたいの」 。「これではダメなんですか ? ( リスト 10 ) 」 マリスト 10 byte 型のダウンカウントによる正しい n 回繰り返しその 2 for(byte i = n 戸 > 0 do—something(i—l 166