如何在 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
,它不会溢出,因为 BigInteger
s 可以任意大。)
如果可以接受第三方库,例如 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 的每个指数的最大基数。
我知道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
,它不会溢出,因为 BigInteger
s 可以任意大。)
如果可以接受第三方库,例如 Guava IntMath.checkedPow
,它满足您的需求。
正如 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 的每个指数的最大基数。