2015/12/10 公開
・オーバーフロー・アンダーフロー
ここでのオーバーフローとは、計算した結果が変数の格納最大値を超えることです。反対に、アンダーフローは変数の格納最小値を下回ることです。これは計算によって得られる理論値を変数に格納できないことを意味していますが、その場合でも変数には何らかの値が格納されます。
このように期待していない計算値が変数に格納されることを未然に防ぐために、適切な変数の型を使ったり、計算処理の前に元の数値の範囲をプログラムでチェックするなどの対処が必要です。
■関連コンテンツ
Javaの変数(他13件) | Javaで扱う変数について解説 |
以下は、変数のオーバーフローが起きるソースプログラムの例です。計算の理論値と変数に格納された値を確認してみてください。
Overflow.java ← クリックしてダウンロードページに移動
001: public class Overflow { 002: public static void main( String[] args ) { 003: // 変数宣言 004: byte a; 005: 006: // 126に1を3回足す 007: a = 126; 008: System.out.println( "理論値=126 変数値=" + a ); 009: ++ a; 010: System.out.println( "理論値=127 変数値=" + a ); 011: ++ a; 012: System.out.println( "理論値=128 変数値=" + a ); 013: ++ a; 014: System.out.println( "理論値=129 変数値=" + a ); 015: System.out.println(); 016: 017: 018: // 変数宣言 019: short b, c, d; 020: 021: b = 50; 022: c = 200; 023: d = (short)( b * c ); 024: System.out.println( "理論値=10000 変数値=" + d ); 025: 026: b = 500; 027: c = 200; 028: d = (short)( b * c ); 029: System.out.println( "理論値=100000 変数値=" + d ); 030: System.out.println(); 031: 032: 033: // 変数宣言 034: double e, f, g; 035: 036: e = 100.0; 037: f = 0.0; 038: g = e / f; 039: System.out.println( "理論値=解なし 変数値=" + g ); 040: System.out.println(); 041: } 042: }
Overflow.javaの出力結果
理論値=126 変数値=126 理論値=127 変数値=127 理論値=128 変数値=-128 理論値=129 変数値=-127 理論値=10000 変数値=10000 理論値=100000 変数値=-31072 理論値=解なし 変数値=Infinity
ここから順番にソースを解説していきます。
003: // 変数宣言 004: byte a; 005: 006: // 126に1を3回足す 007: a = 126; 008: System.out.println( "理論値=126 変数値=" + a ); 009: ++ a; 010: System.out.println( "理論値=127 変数値=" + a ); 011: ++ a; 012: System.out.println( "理論値=128 変数値=" + a ); 013: ++ a; 014: System.out.println( "理論値=129 変数値=" + a ); 015: System.out.println();
これはbyte型のオーバーフローを確認するソースコード例です。
126を代入したbyte型の変数aに1ずつ足していき、理論値と変数値を並べて表示しています。結果、127までは理論値と変数値が同じ値となり、理論値=128で変数値=-128と違う結果になってしまいました。これはbyte型に格納できる値の範囲が-128~127であるため、変数に128が格納できないためです。なぜ、127に1を足した値が-128になるかの説明はここでは省略します。
018: // 変数宣言 019: short b, c, d; 020: 021: b = 50; 022: c = 200; 023: d = (short)( b * c ); 024: System.out.println( "理論値=10000 変数値=" + d ); 025: 026: b = 500; 027: c = 200; 028: d = (short)( b * c ); 029: System.out.println( "理論値=100000 変数値=" + d ); 030: System.out.println();
これはshort型のオーバーフローを確認するソースコード例です。
short型の変数bと変数cに代入した値どうしを掛け算し、その結果をshort型の変数dに代入しています。ソースにd = (short)( b * c );のように型キャストしている理由は、short型の変数どうしの掛け算の結果は、short型より情報量の多い整数の値(int型,long型など)になるため、強制的にshort型に型変換する必要があるためです。(short)を省略した場合には、計算精度が悪くなるという理由でコンパイルエラーになります。
b=50、c=200のときd=10000となりと理論値10000と変数値が一致しています。b=500、c=200のときd=-31072となり理論値100000と不一致となりました。これはshort型に格納できる値の範囲が-32768~32767だからです。なぜ、500と200を掛けた値100000が-31072になるかの説明はここでは省略します。
033: // 変数宣言 034: double e, f, g; 035: 036: e = 100.0; 037: f = 0.0; 038: g = e / f; 039: System.out.println( "理論値=解なし 変数値=" + g ); 040: System.out.println();
これはdouble型のオーバーフローを確認するソースコード例です。
double型の変数eを変数fで割った値を計算し、その結果をdouble型の変数gに代入しています。
この例ではf=0.0なので数学的には割り算の結果は無しとなりますが、Javaの場合は変数gに∞(無限大)が代入されます。それはSyste.out.printlnで"Infinity"(数学での意味は無限大)と表示されることで確認できます。実際のプログラムでは、0での割り算(ゼロ除算)が起こらないように割る数値が0にならないようにチェックし、0であれば割り算を行わないようにします。
ゼロ除算がオーバーフローかどうかは諸説あるようですが、ここではオーバーフローとしています。
■関連コンテンツ
Javaの変数 | Javaで扱う変数について解説 |
無限大 Infinity | 無限大(∞)について |
■新着情報
2022.07.07 | 外部プログラムの実行 | exeファイル実行 |
2022.07.06 | 完全数 | 6=1+2+3 |
■広告