Как я могу обнаружить переполнение целых чисел на 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-битных процессорах, работающих с long
s не менее эффективен, чем работа с int
с (противоположное может быть правдой). Так что если у вас есть выбор между проверкой на переполнение или использованием long
s, пойти на последнее.
Самый простой способ - присвоить значение целочисленной переменной внутри блока try. Если он превышает 32 бита, будет выдано исключение.
Boolean ifExceeds32Bit = CheckIfIntExceeds32Bit(4294967296);
public boolean CheckIfIntExceeds32Bit(int num)
{
try
{
int testVal = num;
return false;
}catch(Exception e)
{
return true;
}
}