Как я могу обнаружить переполнение целых чисел на 32-битных INT?

Я знаю, что такую ​​тему задавали несколько раз, но мой вопрос о переполнении на полных 32 битах int. Например:

  11111111111111111111111111111111 +
  00000000000000000000000000000001 =
  00000000000000000000000000000000   //overflow!

Я нашел тему с похожим вопросом по этому поводу, однако алгоритм не идеален.

  11111111111111111111111111111111 +
  00000000000000000000000000000000 =
  00000000000000000000000000000000  //overflow!

Есть ли простой и быстрый способ проверить это?

6 ответов

Начиная с Java 8, в классе Math есть набор методов:toIntExact(long), addExact(int, int), subtractExact(int, int), multiplyExact(int, int) и версии для long также. Они выдают ArithmeticException, если происходит переполнение, они возвращают правильный результат, если он вписывается в диапазон.

Пример сложения:

int x = 2000000000;
int y = 1000000000;
try {
    int result = Math.addExact(x, y);
    System.out.println("The proper result is " + result);
} catch(ArithmeticException e) {
    System.out.println("Sorry, " + e);
}
long test = (long)x+y;
if (test > Integer.MAX_VALUE || test < Integer.MIN_VALUE)
   // Overflow!

Попробуйте так:

boolean isOverflow(int left, int right) {
    return right > 0
            ? Integer.MAX_VALUE - right < left
            : Integer.MIN_VALUE - right > left;
}

От: https://wiki.sei.cmu.edu/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow

Переполнение может быть обнаружено по логическому выражению старшего значащего бита двух операндов и (усеченному) результату (я взял логическое выражение из руководства по MC68030):

/**
 * Add two int's with overflow detection (r = s + d)
 */
public static int add(int s, 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;
}

Самый интуитивный метод, который я могу придумать: вычислить сумму (или разницу) как long, а затем преобразовать эту сумму в int и посмотрите, изменилось ли его значение.

long longSum = (long) a + b;
int sum = (int) longSum;
if (sum == longSum) {
    // sum contains the correct result
} else {
    // overflow/underflow
}

Помните, что на современных 64-битных процессорах, работающих с longs не менее эффективен, чем работа с intс (противоположное может быть правдой). Так что если у вас есть выбор между проверкой на переполнение или использованием longs, пойти на последнее.

Самый простой способ - присвоить значение целочисленной переменной внутри блока try. Если он превышает 32 бита, будет выдано исключение.

Boolean ifExceeds32Bit = CheckIfIntExceeds32Bit(4294967296);

public boolean CheckIfIntExceeds32Bit(int num)
{

 try
  {
   int testVal = num;
   return false;
  }catch(Exception e)
   {
     return true;
   }
}
Другие вопросы по тегам