Подтвердить что ты не робот

Как обнаружить переполнение по мощности в Java

Я знаю, что java.lang.Math предоставляет набор статических методов для выполнения некоторых операций (sum, difference, multiply, increment, decrement, negate, toInt), бросая ArithmeticException при переполнении.

Есть ли что-то подобное для власти?

4b9b3361

Ответ 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.