Long + Long не больше Long.MAX_VALUE - PullRequest
9 голосов
/ 30 января 2012

Если у меня есть задание

Long c = a + b;

Есть ли простой способ проверить, что a + b не больше / меньше, чем Long.MAX_VALUE / Long.MIN_VALUE?

Ответы [ 4 ]

17 голосов
/ 30 января 2012

Используя Гуава , это так же просто, как

long c = LongMath.checkedAdd(a, b); // throws an ArithmeticException on overflow

, что, на мой взгляд, действительно очень читабельно.(LongMath Javadoc здесь .)

Ради справедливости, я упомяну, что Apache Commons предоставляет ArithmeticUtils.addAndCheck(long, long).

Если выхотите знать, как они работают, ну, ответ - одна строка хакерства для Guava: результат не переполняется, если (a ^ b) < 0 | (a ^ (a + b)) >= 0.Это основано на уловке, что битовое XOR двух чисел неотрицательно, если они имеют один и тот же знак.

Так что (a ^ b) < 0 верно, если a и b имеют разные знаки, и если этона случай, если он никогда не переполнится.Или, если (a ^ (a + b)) >= 0, то a + b имеет тот же знак, что и a, поэтому он не переполняется и не становится отрицательным.

(Чтобы узнать больше подобных уловок, изучите прекрасную книгу Восторг Хакера .)

В Apache используется более сложная тематическая работа, основанная на знаках a и b.

13 голосов
/ 30 января 2012

Это проблема, только если они имеют одинаковый знак (и оба !0), так как в противном случае вы защищены от переполнения. Если произойдет переполнение, знак результата перевернется. Итак:

long r = a + b;
if ( (a < 0 && b < 0 && r >= 0) ||
     (a > 0 && b > 0 && r <= 0) ) {
    // Overflow occurred
}
0 голосов
/ 30 января 2012

простой маршрут:

if(a/2+b/2+(a&b&1)>long.MAX_VALUE/2||a/2+b/2<long.MIN_VALUE/2)...

вам просто нужно надеяться, что он не будет оптимизирован до (a+b)/2

0 голосов
/ 30 января 2012

Один из вариантов - использовать класс BigInteger для точных вычислений, а затем проверить, является ли результат больше или меньше рассматриваемого значения.Например:

if (BigInteger.valueOf(a).add(BigInteger.valueOf(b)).compareTo(BigInteger.valueOf(Long.MAX_VALUE) > 1) {
    /* Overflow occurred. */
} else {
    /* No overflow occurred.
}

Надеюсь, это поможет!

...