Это правильное поведение для округления с BigDecimals? - PullRequest
1 голос
/ 25 апреля 2019

Я пытаюсь округлить BigDecimals следующим образом: 5.46597 -> 5.46, я думал, что код ниже делает это для меня, но нет.

Я пробовал это с BigDecimal.round и BigDecimal.setScale.

BigDecimal bD = new BigDecimal(5.46597); // whole number: 5.4659700000000004393996277940459549427032470703125 
bD.setScale(2, RoundingMode.HALF_DOWN); // 5.47
bD.round(new MathContext(3, RoundingMode.HALF_DOWN)); // 5.47

Разве это не должно быть 5,46, или что я неправильно понял?

Ответы [ 3 ]

10 голосов
/ 25 апреля 2019

HALF_DOWN округляется только тогда, когда фактическое значение находится точно посередине между двумя возможными округленными значениями.Т.е. 5.46500 -> 5.46.С другой стороны, 5.4650000001 -> 5.47, потому что это ближе к 5.47, чем к 5.46.

Возможно, вы ищете RoundingMode.DOWN, который всегда округляется вниз.

4 голосов
/ 25 апреля 2019

Округление с BigDecimal с использованием ROUND_HALF_DOWN определяется в JavaDoc как " ROUND_HALF_DOWN - режим округления до округления до" ближайшего соседа ", если оба соседа не равноудалены, в этом случае округление вниз. " Документация ROUND_HALF_DOWN Документация RoundingMode.HALF_DOWN

Для BigDecimal.valueOf("5.46597").setScale(2, BigDecimal.ROUND_HALF_DOWN) ближайшими соседями являются 5.46 и 5.47 с расстояниями 0.00597 и 0.00403.Таким образом, расстояние до 5.47 меньше (ближе), чем до 5.46, что приводит к округлению до 5.47.

2 голосов
/ 25 апреля 2019

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

Использование

BigDecimal bD = new BigDecimal("5.46597");
bD = bD.setScale(2, RoundingMode.HALF_DOWN); // 5.47

BigDecimal bD = new BigDecimal("5.46500");
bD = bD.setScale(2, RoundingMode.HALF_DOWN); // 5.46

каждый получает точное число с фиксированной точкой с 5 десятичными знаками.

HALF_DOWN округляет до .500000 ... не больше, а только 5-границу.

Логическое округление произойдет до ближайшего целого числа, выше половины будет округлено в большую сторону, ниже половины округлено в меньшую сторону. На точной половине международный математический стандарт гласит: округлять, но логически (на одном и том же расстоянии) это может быть: HALF_UP или HALF_DOWN. Поскольку эффект only относится к точной половине, тестирование не следует проводить с двойным конструктором, который, вероятно, дает значение чуть выше или ниже точной половины.

Также вы забыли назначение.

...