Может удваиваться или переполнение BigDecimal?

Java 8 предоставила нам Math.addExact() для целых чисел, но не десятичных знаков.

Возможно ли переполнение double и BigDecimal? Судя по Double.MAX_VALUE и Как получить наибольшее значение BigDecimal Я бы сказал ответ да.

Таким образом, почему бы нам не иметь Math.addExact() для этих типов? Какой самый удобный способ проверить это сами?

Ответ 1

double переполняется до Infinity и -Infinity, он не обертывается. 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), вероятно, поэтому такой метод addExact не существует в JDK. Конечно, вы всегда можете добавить свою собственную реализацию в класс утилиты в своем собственном приложении.

Ответ 2

Причина, по которой вам не нужна функция 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, с другой стороны, действительно будет переполняться и вызывать соответствующее исключение в этом случае - это вряд ли когда-либо произойдет на практике.

Ответ 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;
}