Может удваиваться или переполнение 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;
}