Тихий убийца Java - переполнение целочисленного типа, осторожно!

Тихий убийца Java - целочисленное переполнение, осторожно!

Хотите верьте, хотите нет, но в Java есть и целочисленное переполнение буфера. Не уверен, что это правильное слово, чтобы описать это или нет, может быть, вы можете предложить некоторые :)

Хорошо, пожалуйста, взгляните на программу ниже, эта программа выводит количество микросекунд в день.

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

Oh.. ответ:500654080. Подождите.. правильный ответ? Правильный ответ должен быть86400000000 !!! Почему Java дает неточный результат? откуда этот номер? Что именно произошло?

Я считаю, что это вызвано переполнением int. Да, переменная long MICROS_PER_DAY имеет достаточно места, чтобы поместиться в большое число, например 86400000000, но она не подходит для int! Максимальное количество int - 2147483647. Внимательно посмотрите на программу выше, вся арифметика ведется в «int», результат повышается до long и присваивается переменной «long MICROS_PER_DAY». According to [JLS 5.1.2], the promotion from int to long is cited as widening primitive conversion which preserves the (incorrect) numerical value.

Однако мы можем избежать вышеупомянутого тихого убийственного переполнения, явно указав «длинное» в первом целом числе, чтобы вся операция превратилась в длинную арифметику.

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, как и ожидалось

Заключение

Эту ошибку так сложно обнаружить или узнать. Иногда это даже невозможно обнаружить. Если кто-то совершит такую ​​ошибку в финансовой системе, я просто не могу представить себе ее последствия. Мой единственный совет - явно приводить примитивный тип при вычислении двух разных типов примитивного типа. Всегда избегайте автоматического расширения примитивного преобразования в любых вычислениях.