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

ああ、答えは5006540​​80です。待って…​答えは正しいですか?正解は 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を期待どおりに印刷します

結論

このバグは検出するのが非常に難しく、気づいていません。時にはそれを検出することも不可能です。誰かがこの種の金融システムで間違いを犯すと、私は結論をイメージングできません。私の唯一のアドバイスは、2つの異なるタイプのプリミティブ型の計算を処理するときに、プリミティブ型を明示的にキャストすることです。任意の計算でプリミティブ変換を自動的に拡大することは避けてください。

次の投稿:Fedoraのパスワードは強いです!!!