Java 8为整数提供了Math.addExact(),但没有针对小数。
double
和BigDecimal
是否可能溢出?根据Double.MAX_VALUE和如何获取最大的BigDecimal值来判断,答案是肯定的。
既然如此,为什么我们不为这些类型提供Math.addExact()
呢?自己检查这一点最可维护的方法是什么?
Java 8为整数提供了Math.addExact(),但没有针对小数。
double
和BigDecimal
是否可能溢出?根据Double.MAX_VALUE和如何获取最大的BigDecimal值来判断,答案是肯定的。
既然如此,为什么我们不为这些类型提供Math.addExact()
呢?自己检查这一点最可维护的方法是什么?
double
会溢出成正无穷或负无穷,而不是环绕回来。 BigDecimal
不会溢出,它的限制仅取决于计算机中的内存量。请参阅:如何获取最大的BigDecimal值
+
和 .addExact
的唯一区别在于它尝试检测是否发生了溢出,并抛出异常而不是环绕。 这是源代码:
public static int addExact(int x, int y) {
int r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
if (((x ^ r) & (y ^ r)) < 0) {
throw new ArithmeticException("integer overflow");
}
return r;
}
如果你想检查溢出是否发生,从某种意义上说,使用 double
更简单,因为你可以简单地检查 Double.POSITIVE_INFINITY
或 Double.NEGATIVE_INFINITY
;对于 int
和 long
,这是一个稍微复杂些的问题,因为它并不总是一个固定的值,但在另一方面,这些可能是输入(例如 Infinity + 10 = Infinity
,在这种情况下您可能不想抛出异常)。
由于所有这些原因(我们甚至还没有提到 NaN
),这可能就是为什么在 JDK 中不存在这样一个addExact
方法。当然,你总是可以在你自己的应用程序中将你自己的实现添加到一个实用类中。
if (r == Double.POSITIVE_INFINITY || r == Double.NEGATIVE_INFINITY)
? - GiliBigDecimal
,从理论上讲你是正确的。但实际上,存在一些实现限制:https://dev59.com/emw15IYBdhLWcg3wJ4is#6792114。 - GiliaddExact
函数的原因是,它不会绕回,而是溢出到Double.Infinity
。Double.POSITIVE_INFINITY + Double.NEGATIVE_INFINITY
为NaN,因此在更复杂的表达式中还必须检查NaN。Math.addExact(Math.addExact(x, y), z)
:double result = x + y + z;
if (Double.isInfinite(result) || Double.isNan(result)) throw ArithmeticException("overflow");
BigDecimal
与之相反,在这种情况下确实会溢出并抛出相应的异常——但在实践中,这种情况非常不可能发生。
Infinity
已经被很好地定义,所以Infinity + 任何除了 -Infinity 的数
仍将是Infinity
。您可以执行任何一系列操作,如果在中间点上溢出,您永远不会得到一个虚假但有效的结果:它总是会成为其中一个无限大或NaN
。这与整数类型相反,因为在整数类型中,可能会发生这种情况。 - biziclopNaN
。 - Voo对于double
,请查看其他答案。
BigDecimal
已经内置了addExact()
保护。 BigDecimal
的许多算术操作方法(例如multiply
)都包含对结果比例的检查:
private int checkScale(long val) {
int asInt = (int)val;
if (asInt != val) {
asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
BigInteger b;
if (intCompact != 0 &&
((b = intVal) == null || b.signum() != 0))
throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
}
return asInt;
}
BigDecimal
的大小可以达到内存所能承载的极限(或者说差不多),因此,虽然它在理论上可能会溢出,在实际应用中不会发生。除非你要计算 Ackermann 函数的值 :) - biziclop