この記事は検証可能な参考文献や出典が全く示されていないか、不十分です。出典を追加して記事の信頼性向上にご協力ください。(このテンプレートの使い方)
出典検索?: "算術オーバーフロー"
算術オーバーフロー(さんじゅつオーバーフロー、英: arithmetic overflow)あるいは単にオーバーフローは、デジタルコンピュータにおいて、演算結果がレジスタの表せる範囲や記憶装置上の格納域に記録できる範囲を超えてしまう現象、またはその結果レジスタ等に格納される値を意味する。オーバーフローは、本来演算結果を格納する場所とは違う場所に格納される場合がある。溢れ(あふれ)とも言う。
符号無し表現の加減算では、最上位桁より上の桁(存在しない桁)への繰り上がり(キャリー)や、おなじく存在しない桁からの繰り下がり(ボロー)が起きることが溢れである。フラグに保存され、キャリーフラグという名が付けられていることが多い。
加算器で2の補数を使って減算を行っていて、加算器のキャリー入出力をそのままとしている場合、繰り下がり(ボロー)のなかった場合にフラグが立ち、繰り下がりがあった場合にはフラグが立たない、というロジックになる(6502・POWER・ARM・PICなど)。加算器#減算器も参照。
符号付き表現の、特に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 命令
伝播
格納できる範囲を超えた値の場合、オーバーフローであることを示す特別な値を格納しておき、その後の演算に伝播させていく。長い計算の最後に値をチェックすればオーバフローが発生したことがわかるので、このような扱い方が便利な場合もある。特にFPUによる浮動小数点数の演算でよく使われる。
無視
最もよくある手法。しかし、結果が不正になるだけでなく、セキュリティホールの原因となることもある。
C言語およびC++では、符号付き整数のオーバーフローは未定義動作を引き起こす[2][3]。そのため、正しい作法にのっとったアプリケーションコードでは、オーバーフローの発生を未然に防がなければならない。符号無し整数はオーバーフローせず、ラップアラウンド(英: wraparound)と呼ばれる動作になることが規定されているが、メモリアドレスに関わるコードや、セキュリティ上重要な意味を持つコードではラップアラウンドも避けるべきとされている[4]。 プログラミング言語や実行環境の中には、算術オーバーフローを検出したときに例外をスローするなど、エラーハンドリングを容易にしてくれるものもある。 C#ではcheckedキーワード(checkedステートメントやchecked演算子)を使うことで、整数演算によってオーバーフローが発生したときSystem.OverflowExceptionがスローされるようになる[5]。ただし浮動小数点演算の場合はスローされない。他にも、整数型Tの引数を受け取るSystem.Math.Abs()メソッドのオーバーロードは、T.MinValueに対してSystem.OverflowExceptionをスローする[6]。 JavaはC#のcheckedに相当する機能を直接持たない。ただし、Java 8でMath
プログラミング環境と算術オーバーフロー
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]。なお、制御ワードの設定はスレッドごとに管理されているため、浮動小数点例外を有効化する場合はスレッドごとに設定が必要となる[17]。
DelphiやC++Builderでは、浮動小数点演算でオーバーフローが発生した場合、System.SysUtils.EOverflowをスローする[18]。ただし、ARMアーキテクチャは浮動小数点例外をサポートしないため、すべての浮動小数点例外がマスクされている[19]。整数演算でオーバーフローが発生した場合、System.SysUtils.EIntOverflowをスローするが、プロジェクトのオーバーフローチェックが有効になっている必要がある[20]。
その他
1996年にあったアリアン5の事故は、オーバーフローを適切に扱っていなかったことが原因である[21]。