Как обнаружить переполнение по мощности в Java
Я знаю, что java.lang.Math предоставляет набор статических методов для выполнения некоторых операций (sum
, difference
, multiply
, increment
, decrement
, negate
, toInt
), бросая ArithmeticException
при переполнении.
Есть ли что-то подобное для власти?
Ответы
Ответ 1
Нет, нет эквивалента для pow
, встроенного в Java. (Единственными pow
методами, встроенными в Java, являются Math.pow
, которые принимают удвоения и не переполняются одинаковыми целыми числами, а BigInteger.pow
, которые не переполняются, поскольку BigInteger
может быть сколь угодно большим.)
Если сторонние библиотеки приемлемы, Guava имеет, например, IntMath.checkedPow
, который делает то, что вы ищете.
Ответ 2
Как Chirag сказал, что целые числа бросают исключения, когда они переполняются, а двойники - нет. Не для того, чтобы стать слишком конкретным, но, в основном, удвоения в памяти хранятся очень похожими на научную нотацию, поскольку они представляют собой целое число * 2 ^ (некоторая мощность) и, следовательно, никогда не переполняются, а умножаются на такие большие или малые 2 ^ некоторая власть), что они полностью теряют свою точность. Поэтому вы можете думать о двойном переполнении, когда они полностью теряют свою точность и печатаются как Infinity
или -Infinity
.
Итак, вам нужно вручную проверить, произошло ли переполнение, проверяя, имеет ли результирующее значение Double.POSITIVE_INFINITY
или Double.NEGATIVE_INFINITY
.
Вот пример кода, чтобы показать, что я имею в виду:
public static void main(String[] args) throws Exception
{
double a = Double.MAX_VALUE; // highest possible double
double b = Double.MAX_VALUE; // highest possible double
if (Math.pow(a, b) == Double.POSITIVE_INFINITY || Math.pow(a, b) == Double.NEGATIVE_INFINITY)
{
throw new ArithmeticException("Double Overflow");
}
}
Ответ 3
Если у вас есть хорошая реализация, вы можете сделать что-то вроде этого:
private static final int[] maxBaseForExponent = IntStream.range(0, 30)
.map(e -> (int) Math.pow(Integer.MAX_VALUE, 1d / e)).toArray();
public static int powExact(int base, int exponent) {
if (exponent < 0) {
throw new ArithmeticException("Negative exponent");
}
if ((base < -1 || base > 1) && (exponent > 30 || base > maxBaseForExponent[exponent])
&& !(base == -2 && exponent == 31)) {
throw new ArithmeticException("Overflow");
}
switch (base) {
case -2:
return (exponent & 1) == 0 ? 1 << exponent : -1 << exponent;
case -1:
return (exponent & 1) == 0 ? 1 : -1;
case 0:
return exponent == 0 ? 1 : 0;
case 1:
return 1;
case 2:
return 1 << exponent;
default:
}
int result = 1;
while (exponent != 0) {
if ((exponent & 1) != 0) {
result *= base;
}
exponent >>= 1;
base *= base;
}
return result;
}
Взял алгоритм из здесь и изменил его, чтобы проверить переполнение, используя массив, который содержит max base для каждого показателя от 0 до 30.
Ответ 4
Целые числа - всего 32 бита. поэтому максимальное значение равно 2 ^ 31 -1. (При использовании BigInteger.pow
. Это менее эффективно.)
Таким образом, вы можете проверить вручную и выбросить исключение, если потребуется
else используйте Math.pow
, который использует double.