简体   繁体   中英

Can doubles or BigDecimal overflow?

Java 8 gave us Math.addExact() for integers but not decimals.

Is it possible for double and BigDecimal to overflow? Judging by Double.MAX_VALUE and How to get biggest BigDecimal value I'd say the answer is yes.

As such, why don't we have Math.addExact() for those types as well? What's the most maintainable way to check this ourselves?

double overflows to Infinity and -Infinity , it doesn't wrap around. BigDecimal doesn't overflow, period, it is only limited by the amount of memory in your computer. See: How to get biggest BigDecimal value

The only difference between + and .addExact is that it attempts to detect if overflow has occurred and throws an Exception instead of wraps. Here's the source code:

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

If you want to check that an overflow has occurred, in one sense it's simpler to do it with double anyway because you can simply check for Double.POSITIVE_INFINITY or Double.NEGATIVE_INFINITY ; in the case of int and long , it's a slightly more complicated matter because it isn't always one fixed value, but in another, these could be inputs (eg Infinity + 10 = Infinity and you probably don't want to throw an exception in this case).

For all these reasons (and we haven't even mentioned NaN yet), this is probably why such an addExact method doesn't exist in the JDK. Of course, you can always add your own implementation to a utility class in your own application.

The reason you do not need a addExact function for floating point digits is because instead of wrapping around, it overflows to Double.Infinity .

Consequently you can very easily check at the end of the operation whether it overflowed or not. Since Double.POSITIVE_INFINITY + Double.NEGATIVE_INFINITY is NaN you also have to check for NaN in case of more complicated expressions.

This is not only faster but also easier to read. Instead of having Math.addExact(Math.addExact(x, y), z) to add 3 doubles together, you can instead write:

double result = x + y + z;
if (Double.isInfinite(result) || Double.isNan(result)) throw ArithmeticException("overflow");

BigDecimal on the other hand will indeed overflow and throw a corresponding exception in that case as well - this is very unlikely to ever happen in practice though.

For double , please check the other answers.

BigDecimal has the addExact() protection already built in. Many arithmetic operation methods (eg multiply ) of BigDecimal contain a check on the scale of the result:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM