算術オーバーフロー(さんじゅつオーバーフロー、: arithmetic overflow)あるいは単にオーバーフローは、デジタルコンピュータにおいて、演算結果がレジスタの表せる範囲や記憶装置上の格納域に記録できる範囲を超えてしまう現象、またはその結果レジスタ等に格納される値を意味する。オーバーフローは、本来演算結果を格納する場所とは違う場所に格納される場合がある。溢れあふれ)とも言う。

符号無し表現の加減算では、最上位桁より上の桁(存在しない桁)への繰り上がり(キャリー)や、おなじく存在しない桁からの繰り下がり(ボロー)が起きることが溢れである。フラグに保存され、キャリーフラグという名が付けられていることが多い。

加算器2の補数を使って減算を行っていて、加算器のキャリー入出力をそのままとしている場合、繰り下がり(ボロー)のなかった場合にフラグが立ち、繰り下がりがあった場合にはフラグが立たない、というロジックになる(6502POWERARMPICなど)。加算器#減算器も参照。

符号付き表現の、特に2の補数表現では、加減算のビット操作は符号無し表現のそれと全く同じであるが、最上位桁より上の桁との繰り上がりや繰り下がりではなく、最上位桁への繰り上がりや繰り下がりが溢れであることがある。最上位桁への繰り上がりや繰り下がりと同時に最上位桁より上の桁への繰り上がりや繰り下がりがあったら溢れではない。これのフラグはオーバーフローフラグという名が付けられていることが多い。

3ビットで+1を繰り返した場合でそれぞれの例を示す。

  • 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 →(X)→ 0 ...
  • 0 → 1 → 2 → 3 →(Y)→ -4 → -3 → -2 → -1 →(YX)→ 0 ...

(X)と(YX)で最上位桁より上の桁への繰り上がりが起きている。(Y)と(YX)では最上位桁への繰り上がりが起きている。

浮動小数点数では、演算の結果、指数部が最大より大きくなった場合がオーバーフローで、結果が±(正または負の無限大、+INFあるいは-INF)になる。

オーバーフローの処理方法 編集

オーバーフローの処理方法はいくつかある。

設計時の配慮
正しいデータ型(大きさと符号の有無)を選択する。
発生を未然に防ぐ
演算を注意深く並べ、必要に応じてオペランドを事前チェックすることによって、演算結果がオーバフローすることを防止する。
発生時の処理
オーバフロー発生時にその場で処理をする。例えば、2バイトの数値を1バイト毎の加算で加算する場合、まず下の桁(バイト)を加算して次に上の桁を加算する。このとき下の桁の加算でキャリーが発生した場合、上の桁の加算にキャリーのぶんも加算しなければならない。CPUには一般にそのような場合を検出する方法があり(ステータスレジスタ参照)、レジスタより大きな数の演算をサポートできるようになっている。例えば、Intel 8086の場合、オーバーフロー検知用のINTO 命令英語版を実行することでオーバーフローフラグをチェックし、セットされている場合には、オーバーフロー例外を発生する[1]
伝播
格納できる範囲を超えた値の場合、オーバーフローであることを示す特別な値を格納しておき、その後の演算に伝播させていく。長い計算の最後に値をチェックすればオーバフローが発生したことがわかるので、このような扱い方が便利な場合もある。特にFPUによる浮動小数点数の演算でよく使われる。
無視
最もよくある手法。しかし、結果が不正になるだけでなく、セキュリティホールの原因となることもある。

C言語およびC++では、符号付き整数のオーバーフローは未定義動作を引き起こす[2][3]。そのため、正しい作法にのっとったアプリケーションコードでは、オーバーフローの発生を未然に防がなければならない。符号無し整数はオーバーフローせず、ラップアラウンドと呼ばれる動作になることが規定されているが、メモリアドレスに関わるコードや、セキュリティ上重要な意味を持つコードではラップアラウンドも避けるべきとされている[4]

プログラミング環境と算術オーバーフロー 編集

プログラミング言語や実行環境の中には、算術オーバーフローを検出したときに例外をスローするなど、エラーハンドリングを容易にしてくれるものもある。

C#ではcheckedキーワード(checkedステートメントやchecked演算子)を使うことで、整数演算によってオーバーフローが発生したときSystem.OverflowExceptionがスローされるようになる[5]。ただし浮動小数点演算の場合はスローされない。他にも、整数型Tの引数を受け取るSystem.Math.Abs()メソッドのオーバーロードは、T.MinValueに対してSystem.OverflowExceptionをスローする[6]

JavaはC#のcheckedに相当する機能を直接持たない。ただし、Java 8でMathクラスに追加されたExactメソッドを使うと、オーバーフローが発生したときにArithmeticExceptionがスローされる。

ISO C/C++では、SIGFPEシグナルがサポートされている[7]。シグナルハンドラーを設定すると、POSIXではオーバーフロー発生時にFPE_INTOVFまたはFPE_FLTOVFのコードが発生する[8]C++BuilderではFPE_INTOVFLOWまたはFPE_OVERFLOWとなる[9]Microsoft Visual C++では整数オーバーフローによるシグナルは発生せず、浮動小数点数オーバーフロー発生時に_FPE_OVERFLOWのコードが発生する[10]。ただし、SIGFPEのシグナルハンドラーからは復帰するべきではなく、そのまま終了するべきとされている[11]

C99およびC++11では、直前の演算によって浮動小数点例外が発生したかどうかをチェックできるテスト関数fetestexcept()を標準化している[12][13]。オーバーフローを検出するにはテストビットとしてFE_OVERFLOWを使用する[14]

Microsoft Visual C++のランタイムライブラリは、デフォルトではすべての浮動小数点例外をマスクしているが、_controlfp_s()関数などを使ってオーバーフローの浮動小数点例外を有効化すると、Microsoft Windows固有のエラー処理機構である構造化例外[15]をスローするようになる[16]

DelphiC++Builderでは、浮動小数点演算でオーバーフローが発生した場合、System.SysUtils.EOverflowをスローする[17]。ただし、ARMアーキテクチャは浮動小数点例外をサポートしないため、すべての浮動小数点例外がマスクされている[18]。整数演算でオーバーフローが発生した場合、System.SysUtils.EIntOverflowをスローするが、プロジェクトのオーバーフローチェックが有効になっている必要がある[19]

その他 編集

  • 1996年にあったアリアン5の事故は、オーバーフローを適切に扱っていなかったことが原因である[20]
  • 電卓の画面は一般的に十進数で表示されるが、電卓でも計算の結果オーバーフローが発生する場合がある(8桁電卓の99999999+1など)。これについての詳細は電卓#エラー表示についてを参照。

脚注 編集

  1. ^ 田辺皓正編著『マイクロコンピュータシリーズ15 8086マイクロコンピュータ』丸善株式会社、1983年4月30日、83頁。 
  2. ^ MSC15-C. 未定義の動作に依存しない
  3. ^ Tell Programmers About Signed Integer Overflow Behavior
  4. ^ INT30-C. 符号無し整数の演算結果がラップアラウンドしないようにする
  5. ^ checked および unchecked ステートメント - オーバーフローチェック コンテキストを制御します - C# | Microsoft Learn
  6. ^ Math.Abs Method (System) | Microsoft Learn
  7. ^ SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE - cppreference.com
  8. ^ <signal.h> - IEEE Std 1003.1-2017
  9. ^ signal(C RTL) - RAD Studio
  10. ^ _fpreset | Microsoft Learn
  11. ^ SIG35-C. シグナルハンドラ SIGSEGV、SIGILL、SIGFPE から復帰しない
  12. ^ FLP03-C. 浮動小数点エラーを検知して処理する
  13. ^ fetestexcept - cpprefjp C++日本語リファレンス
  14. ^ FE_OVERFLOW - cpprefjp C++日本語リファレンス
  15. ^ Structured Exception Handling - Win32 apps | Microsoft Learn
  16. ^ _controlfp_s | Microsoft Learn
  17. ^ 浮動小数点例外 - RAD Studio
  18. ^ 浮動小数点演算について - RAD Studio
  19. ^ System.SysUtils.EIntOverflow - RAD Studio API Documentation
  20. ^ 失敗百選-アリアン5型ロケット爆発事故

関連項目 編集