6

これらのforループは、アルゴリズムの正式な正当性証明の最初の基本的な例の 1 つです。それらには、異なるが同等の終了条件があります。

1   for ( int i = 0; i != N; ++i )

2   for ( int i = 0; i < N; ++i )

違いは事後条件で明らかになります。

  • i == N最初のものは、ループが終了した後の強力な保証を提供します。

  • 2番目のものは、ループが終了した後の弱い保証を与えるだけi >= Nですが、それを仮定したくなるでしょうi == N.

何らかの理由でインクリメント++iが のようなものに変更されたi += 2場合i、またはループ内で変更された場合、またはNが負の場合、プログラムは失敗する可能性があります。

  • 最初のものは無限ループに陥る可能性があります。エラーのあるループの早い段階で失敗します。デバッグは簡単です。

  • 2 番目のループは終了し、後で間違った仮定のためにプログラムが失敗する可能性がありますi == N。バグの原因となったループから遠く離れた場所で失敗する可能性があり、追跡が困難になります。または、予想外のことを静かに続けてしまうこともあり、これはさらに悪いことです。

あなたはどの終了条件を好みますか、またその理由は何ですか? 他の考慮事項はありますか?これを知っている多くのプログラマーが、なぜそれを適用することを拒否するのでしょうか?

4

13 に答える 13

4

私は2番目の形式を使用する傾向があります。これは、ループが確実に終了するためです。つまり、ループ内でiを変更することによって、非終了バグを導入するのは困難です。

もちろん、入力する文字が1つ少ないという少し怠惰な利点もあります;)

また、適切なスコープルールを備えた言語では、iがループ構造内で宣言されているため、ループ外では使用できないようにする必要があると主張します。これにより、ループの最後でiがNに等しいという依存が緩和されます...

于 2008-09-25T08:57:54.403 に答える
2

カウンターを単独で見る必要はありません。何らかの理由で誰かがカウンターのインクリメント方法を変更した場合、i==N に必要な場合は終了条件と結果のロジックが変更されます。

より標準的であり、無限ループにならないため、2番目の条件をお勧めします。

于 2008-09-25T08:45:34.573 に答える
1

ループ内で何が起こっているのかを理解するのに役立つので、ほとんどのプログラマーは2番目のものを使用すると思います。私はそれを見ることができ、私が0から始まり、間違いなくN未満になることを「知っています」。

最初のバリアントにはこの品質がありません。私はそれを見ることができます、そして私が知っているのは私が0から始めて、それがNに等しくなることは決してないということだけです。それほど役に立ちません。

ループをどのように終了するかに関係なく、ループの外側でループ制御変数を使用する場合は常に注意が必要です。あなたの例では、あなたは(正しく)ループの内側でiを宣言しているので、ループの外側のスコープにはなく、その値の問題は議論の余地があります...

もちろん、2番目のバリアントには、私が見たすべてのC参照が使用するものであるという利点もあります:-)

于 2008-09-25T08:49:58.883 に答える
1

C++ では、!=一般性のためにテストを使用することをお勧めします。C++ のイテレータには、入力イテレータフォワード イテレータ双方向イテレータランダム アクセス イテレータなどのさまざまな概念があり、それぞれが前のイテレータを新しい機能で拡張します。機能するには<、ランダムアクセス反復子が必要ですが、!=入力反復子だけが必要です。

于 2008-09-25T08:45:30.873 に答える
1

コードを信頼できる場合は、どちらでもかまいません。

コードを読みやすく、簡単に理解できるようにしたい場合 (したがって、変人であると想定しなければならない人からの変更に対してより寛容になるようにしたい場合)、次のようなものを使用します。

for ( int i = 0 ; i >= 0 && i < N ; ++i) 
于 2008-09-25T08:45:54.273 に答える
1

ループが終了することを確認できるので、私は常に #2 を使用します...後で N と等しいことに依存することは、副作用に依存しています...変数 N 自体を使用したほうがよいのではないでしょうか?

[編集] 申し訳ありません...私は#2を意味しました

于 2008-09-25T08:46:14.243 に答える
0

一般的に私は好む

for ( int i = 0; i < N; ++i )

本番環境でのバグのあるプログラムに対する罰は、それほど深刻ではないようです。forループでスレッドが永久にスタックすることはありません。この状況は、非常にリスクが高く、診断が非常に難しい場合があります。

また、一般的に、私はこれらの種類のループを避けて、より読みやすいforeachスタイルのループを優先します。

于 2008-09-25T08:49:23.470 に答える
0

私は#2を使用することを好みます。これは、iの意味をforループの外に拡張しないようにするためです。そのような変数を追跡している場合は、追加のテストを作成します。これは冗長または非効率的であると言う人もいるかもしれませんが、それは読者に私の意図を思い出させます:この時点で、私はNに等しくなければなりません

@timyates-副作用に頼るべきではないことに同意します

于 2008-09-25T08:50:33.763 に答える
0

両者の違いはよくおっしゃっていたと思います。ただし、次のコメントがあります。

  • これは「言語に依存しない」ものではありません。例はC++であることがわかりますが、ループ内のループ変数を変更できない言語や、インデックスの値が後で使用できることを保証しない言語があります。ループ(および一部は両方を実行します)。

  • i 内でインデックスを宣言したので、ループ後のfor値には賭けません。例は、それが明確なループであると暗黙のiうちに想定しているため、少し誤解を招く可能性があります。for実際には、これはより便利な書き方です。

    // version 1
    { int i = 0;
      while (i != N) {
        ...
        ++i;
      }
    }
    

    iブロック後にどのように未定義であるかに注意してください。

iプログラマーが上記のすべてがの値の一般的な仮定を行わず、終了条件として選択するのに十分賢明であることを知っていれば、i<N終了条件が最終的に満たされることを保証します。

于 2008-09-25T08:59:31.683 に答える
0

上記のいずれかを c# で使用すると、ループの外側で i を使用するとコンパイラ エラーが発生します。

于 2008-09-25T09:20:56.843 に答える
0

私は時々これを好みます:

for (int i = 0; (i <= (n-1)); i++) { ... }

このバージョンは、私が持つことができる値の範囲を直接示しています。範囲の下限と上限のチェックに関する私の見解は、これが本当に必要な場合、コードには副作用が多すぎて書き直す必要があるということです。

他のバージョン:

for (int i = 1; (i <= n); i++) { ... }

ループ本体が呼び出される頻度を判断するのに役立ちます。これには有効なユースケースもあります。

于 2008-09-25T09:23:02.377 に答える
0

一般的なプログラミング作業については、私が好む

for ( int i = 0; i < N; ++i )

for ( int i = 0; i != N; ++i )

特にコードがリファクタリングされた場合に、エラーが発生しにくいためです。この種のコードが誤って無限ループになってしまうのを見たことがあります。

その議論は、「あなたは i == N と仮定したくなるだろう」というものでしたが、私はそれが真実だとは思いません。私はその仮定をしたことも、他のプログラマーがそれを行うのを見たこともありません。

于 2009-10-17T01:06:29.370 に答える
0

正式な検証と自動終了分析の観点から、私は #2 ( <) を強く好みます。一部の変数が増加したことを追跡するのは非常に簡単です(非負の数の前var = x、後)。しかし、それが最終的に成り立つかどうかは、それほど簡単ではありません。このためには、 が各ステップで正確に増加すると推測する必要がありますが、(より複雑な例では) 抽象化のために失われる可能性があります。var = x+nni==Ni1

2 ずつインクリメントするループ ( ) について考えるとi = i + 2、この一般的な考え方がより理解できるようになります。終了を保証するには、 を知る必要がありますが、条件としてi%2 == N%2使用する場合は関係ありません。<

于 2012-10-17T15:27:11.850 に答える