Как читать большой файл построчно

Ну, что касается примитивных целых типов, Java не обрабатывает Over / Underflow вообще (для float и double поведение отличается, оно будет выравниваться до +/- бесконечности, как и мандаты IEEE-754).

При добавлении двух int, вы не получите никаких указаний при переполнении. Простым методом проверки переполнения является использование следующего более крупного типа для фактического выполнения операции и проверки того, остается ли результат в диапазоне для типа источника:

public int addWithOverflowCheck(int a, int b) {
    // the cast of a is required, to make the + work with long precision,
    // if we just added (a + b) the addition would use int precision and
    // the result would be cast to long afterwards!
    long result = ((long) a) + b;
    if (result > Integer.MAX_VALUE) {
         throw new RuntimeException("Overflow occured");
    } else if (result < Integer.MIN_VALUE) {
         throw new RuntimeException("Underflow occured");
    }
    // at this point we can safely cast back to int, we checked before
    // that the value will be withing int's limits
    return (int) result;
}

Что вы сделали бы вместо предложения throw, зависит от ваших требований к приложениям (throw, flush to min / max или просто записывать все). Если вы хотите обнаружить переполнение при длительных операциях, вам не повезло с примитивами, вместо этого используйте BigInteger.


Edit (2014-05-21): Поскольку этот вопрос, похоже, относится к довольно часто, и мне приходилось решать ту же проблему самостоятельно, ее довольно легко оценить условие переполнения тем же методом, что и ЦП будет вычислять свой флаг V.

В основном это булевское выражение, которое включает в себя знак обоих операндов, а также результат:

/**
 * Add two int's with overflow detection (r = s + d)
 */
public static int add(final int s, final int d) throws ArithmeticException {
    int r = s + d;
    if (((s & d & ~r) | (~s & ~d & r)) < 0)
        throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");    
    return r;
}

В java его проще применить выражение (в if) ко всем 32 битам и проверить результат с использованием & lt; 0 (это будет эффективно проверять бит знака). Принцип работает точно так же для всех целых примитивных типов , изменяя все объявления в вышеописанном методе на long, заставляет его работать долго.

Для меньших типов из-за неявного преобразования в int (см. JLS для побитовых операций для деталей), вместо проверки & lt; 0, проверка должна маскировать знаковый бит явно (0x8000 для коротких операндов, 0x80 для операндов байтов, соответствующим образом корректировать приведения и объявление параметров):

/**
 * Subtract two short's with overflow detection (r = d - s)
 */
public static short sub(final short d, final short s) throws ArithmeticException {
    int r = d - s;
    if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
        throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
    return (short) r;
}

(Обратите внимание, что в приведенном выше примере используется выражение для вычесть обнаружение переполнения)


Итак, как / почему эти булевы выражения работают? Во-первых, некоторое логическое мышление показывает, что переполнение может быть только , если знаки обоих аргументов одинаковы. Поскольку, если один аргумент отрицательный и один положительный, результат (добавления) должен быть ближе к нулю, или в крайнем случае один аргумент равен нулю, такой же, как и другой аргумент. Поскольку сами аргументы не могут создать условие переполнения, их сумма также не может создать переполнение.

Итак, что произойдет, если оба аргумента имеют один и тот же знак? Давайте рассмотрим случай, который положителен: добавление двух аргументов, которые создают сумму, большую, чем типы MAX_VALUE, всегда будет давать отрицательное значение, поэтому происходит переполнение , если arg1 + arg2> MAX_VALUE. Теперь максимальное значение, которое может получиться, будет MAX_VALUE + MAX_VALUE (в крайнем случае оба аргумента MAX_VALUE). Для байта (пример), который будет означать 127 + 127 = 254. Рассматривая представления бит всех значений, которые могут возникнуть в результате добавления двух положительных значений, можно обнаружить, что для тех, у которых переполнение (от 128 до 254) установлено бит 7, в то время как все, что не переполняется (от 0 до 127), имеют бит 7 (верхний, знак), очищенный. То, что проверяет первая (правая) часть выражения:

if (((s & d & ~r) | (~s & ~d & r)) < 0)

(~ s & amp; ~ d & amp; r) становится истинным, , только если , оба операнда (s, d) положительны, а результат (r) отрицателен (выражение работает на всех 32 битах, но единственный бит, который нам интересен, является самым верхним (знаковым) битом, который проверяется на & lt; 0 ).

Теперь, если оба аргумента отрицательны, их сумма никогда не может быть ближе к нулю, чем любой из аргументов, сумма должна быть ближе к минусовой бесконечности. Самое экстремальное значение, которое мы можем произвести, - MIN_VALUE + MIN_VALUE, которое (опять-таки для байтового примера) показывает, что для любого значения диапазона (от -1 до -128) бит знака устанавливается, а любое возможное переполняющее значение (от -129 до -256 ) имеет бит знака, очищенный. Таким образом, знак результата снова показывает условие переполнения. То, что левая половина (s & amp; d & amp; ~ r) проверяет случай, когда оба аргумента (s, d) отрицательны и результат положительный. Логика в значительной степени эквивалентна положительному случаю; все битовые шаблоны, которые могут возникнуть в результате добавления двух отрицательных значений, будут иметь бит знака, очищенный тогда и только тогда, когда произошло недополнение.

503
задан wjandrea 2 July 2019 в 03:01
поделиться