web-dev-qa-db-ja.com

オフバイワンエラーとは何ですか?どうすれば修正できますか?

オフバイワンエラーとは何ですか?持っている場合、どうすれば修正できますか?

24
Dina

off-by-one error は、たとえば、ループをn回実行して、次のような書き込みを行う場合です。

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

または:

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

最初のケースでは、ループが実行されます(n - 1)回、2番目のケースでは(n + 1)回、名前を1つずつ付けます。他のバリエーションも可能ですが、一般に、ループ変数の初期値またはループの終了条件のエラーにより、ループの実行回数が多すぎたり少なすぎたりします。

ループは次のように正しく記述できます。

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

Forループは、whileループの特殊なケースです。同じ種類のエラーがwhileループで発生する可能性があります。

45
Mark Byers

一部の言語はゼロからのベクトルを列挙し(たとえばC)、他の言語は1から列挙するため(たとえばR)、一般的な1つずつの混乱が発生します。したがって、サイズxのベクトルnには、Cではx[0]からx[n-1]まで、Rではx[1]からx[n]まで実行されるメンバーがあります。 。

また、周期的なインクリメントの一般的なイディオムをコーディングするときに、オフバイワンの課題に直面します。

Cの場合:

i = (i+1)%n

Rの場合:

i <- (i-1)%%n + 1
2
Niels Holst

配列とforループを特徴とする次のコードがあるとします。

char exampleArray[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };

for(int i = 0; i <= 11; i++)
{
  print(exampleArray[i])
}

ここで問題を参照してください?配列に11文字が含まれているとカウントしたため、ループを11回繰り返すように設定しました。ただし、ほとんどの言語では配列はゼロから始まります。つまり、コードが出力されるときです。

exampleArray[11]

例の配列にはインデックス11に値がないため、インデックスの範囲外エラーが発生します。

この場合、ループに1回少なく繰り返すように指示するだけで、これを簡単に修正できます。

この問題をデバッグする最も簡単な方法は、上限と下限を出力し、どの値が範囲外のインデックスエラーを生成するかを確認してから、反復全体で値を1つ大きくまたは1つ小さく設定することです。

もちろん、これは、エラーが配列の境界を1つ超える、または1つ下回るループによって生成されることを前提としています。インデックスの範囲外エラーが発生する可能性がある他の状況もありますが、これが最も一般的なケースです。範囲外のインデックスは、過去の境界がデータの境界内にないためにデータが存在しないデータにアクセスしようとすることを常に指します。

1
Vapidant

オフバイワンエラーは、値がNであると予想される場合ですが、実際にはN-1またはN +1になります。たとえば、プログラムが10回の操作を実行することを期待していましたが、最終的には9回または11回(1回は少なすぎるか1回は多すぎる)実行されます。プログラミングでは、これは「for」ループを処理するときに最も一般的に発生します。

このエラーは、カウントを追跡するために使用している数が、カウントしているものの数と同じでない可能性があることに気付いていないという誤った判断が原因で発生します。言い換えれば、あなたが数えるために使用している数はあなたが数えているものの合計と同じではないかもしれません。両方が同じであることを義務付けるものは何もありません。 0から10まで大声で数えようとすると、合計11の数字を言うことになりますが、最後に言う数字は10です。

この問題を防ぐ1つの方法は、私たちの脳にはそのエラーを起こす傾向(おそらく認知バイアス)があることを認識することです。このことを念頭に置いておくと、将来の状況を特定して防止するのに役立つ場合があります。しかし、このエラーを防ぐためにできる最善のことは、 ユニットテスト と書くことだと思います。テストは、コードが正常に実行されていることを確認するのに役立ちます。

0
Pedro Pinheiro