BigDecimal умножить на ноль


Я выполняю простое умножение с BigDecimal, и я нашел какое-то странное поведение при умножении на ноль (умножение на ноль правильно в этом случае использования).

Базовая математика говорит мне, что все, умноженное на ноль, будет равно нулю (см.: Нулевое Свойство Продукта и Свойства Умножения)

однако следующий код будет последовательно отказывать с тем же ошибка:

assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0)));
java.lang.AssertionError: 
Expected :0
Actual   :0E-48

это неточность с BigDecimal или есть какая-то нишевая ветвь математики, которую я где-то упускаю?

Примечания: JDK 1.6.0_27 работает в IntelliJ 11

3 58

3 ответа:

вы не можете использовать equals() метод сравнения BigDecimals, как это утверждение делает. Это потому, что эта функция equals будет сравнивать масштаб. Если масштаб отличается,equals() вернет false, даже если они являются одним и тем же числом математически.

однако, вы можете использовать compareTo() делать то, что вы хотите:

как указывает @assylias, вы также должны использовать new BigDecimal("22.3") конструктор чтобы избежать проблем с двойной точностью.

BigDecimal expected = BigDecimal.ZERO;
BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO);
assertEquals(0, expected.compareTo(actual));

существует также метод, называемый signum(), которая возвращает -1, 0 или 1 для отрицательного, нулевого и положительного. Таким образом, вы также можете проверить на ноль с

assertEquals(0, actual.signum());

есть 2 проблемы с вашим кодом:

  • вы должны сравнить BigDecimal с compareTo вместо equals, как советуют другие ответы
  • но вы также должны использовать string конструктор: new BigDecimal("22.3") вместо двойного конструктора new BigDecimal(22.3) чтобы избежать проблем с двойной точностью

другими словами, следующий код (который правильно использует compareTo) по-прежнему возвращает false:

BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10));
System.out.println(bd.compareTo(BigDecimal.ONE) == 0);

, потому что 0.1d * 10d != 1

equals() on BigDecimal проверяет внутреннее состояние BigDecimal для сравнения

см. код ниже

public boolean equals(Object x) {
    if (!(x instanceof BigDecimal))
        return false;
    BigDecimal xDec = (BigDecimal) x;
    if (x == this)
        return true;
    if (scale != xDec.scale)
        return false;
    long s = this.intCompact;
    long xs = xDec.intCompact;
    if (s != INFLATED) {
        if (xs == INFLATED)
            xs = compactValFor(xDec.intVal);
        return xs == s;
    } else if (xs != INFLATED)
        return xs == compactValFor(this.intVal);

    return this.inflate().equals(xDec.inflate());
}

если вы хотите сравнить значения использовать compareTo()

изменить ваш код

assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0)));

обновление:

использовать конструктор, принимающий строку в качестве параметра для BigDecimal для точности в точности проверьте связанные ссылки ниже


См. Также