算術オーバーフローとアンダーフローを防ぐための最も効果的な方法は何ですか?
頭に浮かぶいくつかの例は次のとおりです。
- 有効な入力範囲に基づくテスト
- 正式な方法を使用した検証
- 不変式の使用
- 言語機能またはライブラリを使用した実行時の検出 (これはそれを防ぎません)
1 つの可能性は、オーバーフロー/アンダーフローしない任意のサイズの整数を持つ言語を使用することです。
それ以外の場合は、これが本当に懸念事項であり、言語で許可されている場合は、整数のように動作するラッパー クラスを記述しますが、すべての操作でオーバーフローをチェックします。デバッグ ビルドのチェックを行い、リリース ビルド用に最適化したままにすることもできます。C++ のような言語では、これを行うことができ、リリース ビルドの場合は整数とほぼ同じように動作しますが、デバッグ ビルドの場合は完全な実行時チェックが行われます。
class CheckedInt
{
private:
int Value;
public:
// Constructor
CheckedInt(int src) : Value(src) {}
// Conversions back to int
operator int&() { return Value; }
operator const int &() const { return Value; }
// Operators
CheckedInt operator+(CheckedInt rhs) const
{
if (rhs.Value < 0 && rhs.Value + Value > Value)
throw OverflowException();
if (rhs.Value > 0 && rhs.Value + Value < Value)
throw OverflowException();
return CheckedInt(rhs.Value + Value);
}
// Lots more operators...
};
編集:
誰かがすでに C++ でこれを行っていることが判明しました。現在の実装は Visual Studio に焦点を当てていますが、gcc のサポートも取得しているようです。
あなたのリストには、非常に重要な選択肢が 1 つ欠けていると思います。それは、仕事に適したプログラミング言語を選択することです。固定サイズの整数がないため、これらの問題がないプログラミング言語が多数あります。
コードの範囲/有効性チェックを行うために、多くのテスト コードを作成します。これは、これらのタイプの状況のほとんどをキャッチする傾向があり、防弾コードを書くのに確実に役立ちます。
long doubleのような高精度の浮動小数点数を使用します。
多くの場合、不整合をチェックするラッパーは理にかなっています。2つ以上の整数に対する加算演算(つまり、加算または乗算)の結果がオペランドよりも小さい場合は、問題が発生したことがわかります。すべての加算操作の後には、
if (sum < operand1 || sum < operand2)
omg_error();
同様に、論理的に小さい値になるはずの操作は、誤って曖昧にされていないかどうかを確認する必要があります。
コードをチェックして、オーバーフローがないことを証明する形式メソッドの使用を調査しましたか? 抽象解釈として知られる正式な方法の手法は、ソフトウェアの堅牢性をチェックして、ソフトウェアがオーバーフロー、アンダーフロー、ゼロ除算、オーバーフロー、またはその他の同様の実行時エラーに悩まされていないことを証明できます。これは、ソフトウェアを徹底的に分析する数学的手法です。この技術は、1970 年代にパトリック・クーゾによって開発されました。オーバーフローがロケットの破壊を引き起こした Arian 5 ロケットのオーバーフロー状態を診断するために使用され、成功しました。浮動小数点数を整数に変換中にオーバーフローが発生しました。この手法の詳細については、こちらとWikipediaを参照してください。
使用する言語を選択する際には、整数のサイズよりも重要な考慮事項があります。値が境界内にあるかどうかわからない場合は入力を確認するか、非常にまれな場合は例外処理を使用してください。