Javaのサイレントキラー – 整数オーバーフロー、注意深い!
信じられないかもしれませんが、Javaには整数のバッファオーバーフローも含まれています。私はこれを記述するための正しい単語であるかどうか、あなたがいくつか示唆することができるかもしれません:)
OK、以下のプログラムを見てください。このプログラムは1日のマイクロ秒数を表示します。
public class JavaLongOverflow { public static void main(String[]args) { final long MICROS__PER__DAY = 24 ** 60 ** 60 ** 1000 ** 1000; System.out.println("MICROS__PER__DAY : " + MICROS__PER__DAY); } }
結果
MICROS__PER__DAY : 500654080
ああ、答えは500654080です。待って…答えは正しいですか?正解は
86400000000
にする必要があります。なぜJavaが私に不正確な結果を与えるのでしょうか?この番号はどこから来たのですか?正確に何が起こったのですか?
私はこれが “int”オーバーフローの原因だと信じています。はい、「長いMICROS
PER
DAY」変数には、86400000000などの大きな数に収まるだけのスペースがありますが、「int」に収まらないのです! “int”の最大数は2147483647です。上記のプログラムに注意してください。算術演算全体が “int”で、結果はlongに昇格し、 “long MICROS
PER
DAY”変数に代入されます。 ** [JLS 5.1.2]によれば、intからlongへのプロモーションは、(不正確な)数値を保持する拡大プリミティブ変換として引用されています。
しかし、最初の整数の “long”を明示的に指定することで、サイレントキラーのオーバーフローを避けることができます。
public class JavaLongOverflow { public static void main(String[]args) { final long MICROS__PER__DAY = 24L ** 60 ** 60 ** 1000 ** 1000; System.out.println("MICROS__PER__DAY : " + MICROS__PER__DAY); } }
結果
MICROS__PER__DAY : 86400000000
上記のプログラムは86400000000を期待どおりに印刷します