如何在 Java 中检测电源溢出

How to detect overflow on power in Java

我知道java.lang.Math提供了一组静态方法来执行一些操作(sum,difference,multiply, increment, decrement, negate, toInt), 在溢出时抛出 ArithmeticException

电源有类似的东西吗?

整数只有 32 位。所以最大值是 2^31 -1。 (如果使用 BigInteger.pow。效率较低。) 所以你可以手动检查并在需要时抛出异常 否则使用 Math.pow,它使用 double.

不,Java 中没有与 pow 等效的东西。 (Java 中内置的唯一 pow 方法是 Math.pow,它接受双精度数并且不会像整数一样溢出,以及 BigInteger.pow,它不会溢出,因为 BigIntegers 可以任意大。)

如果可以接受第三方库,例如 Guava IntMath.checkedPow,它满足您的需求。

正如 所说,整数在溢出时会抛出异常,而双精度则不会。不要太具体,但基本上,内存中的双精度数与科学计数法非常相似,因为它们是一些整数 * 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");
    }
}

如果有自己的实现没问题,你可以这样做:

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;
}

here 中获取算法并对其进行修改以使用数组检查溢出,该数组包含从 0 到 30 的每个指数的最大基数。