Java 8给了我们Math.addExact()的整数但不是小数。
double
和BigDecimal
是否有可能溢出?从Double.MAX_VALUE和How to get biggest BigDecimal value判断,我会说答案是肯定的。
因此,我们为什么不为这些类型提供Math.addExact()
?什么是最可维护的方式来检查这个?
答案 0 :(得分:12)
double
溢出到Infinity
和-Infinity
,它没有包围。 BigDecimal
不会溢出,期间,它仅受计算机内存量的限制。请参阅:How to get biggest BigDecimal value
+
和.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
的情况下,它稍微复杂一点,因为它不总是一个固定值,但在另一个中,这些可能是输入(例如{{1}你可能不想在这种情况下抛出异常。)
由于所有这些原因(我们甚至还没有提到Infinity + 10 = Infinity
),这可能就是为什么这样的NaN
方法在JDK中不存在。当然,您始终可以将自己的实现添加到自己的应用程序中的实用程序类中。
答案 1 :(得分:4)
对于浮点数不需要addExact
函数的原因是因为它不是环绕,而是溢出到Double.Infinity
。
因此,您可以非常轻松地在操作结束时检查 是否溢出。由于Double.POSITIVE_INFINITY + Double.NEGATIVE_INFINITY
是NaN,因此在表达更复杂的情况下还必须检查NaN。
这不仅更快,而且更容易阅读。您可以改为编写:
,而不是让Math.addExact(Math.addExact(x, y), z)
一起添加3个双打
double result = x + y + z;
if (Double.isInfinite(result) || Double.isNan(result)) throw ArithmeticException("overflow");
另一方面, BigDecimal
确实会溢出并在这种情况下抛出相应的异常 - 但这在实践中不太可能发生。
答案 2 :(得分:3)
double
,请查看其他答案。
BigDecimal
已经内置了addExact()
保护。multiply
的许多算术运算方法(例如BigDecimal
)都包含对结果范围的检查:
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;
}