Как бороться с роудингом в BigDecimal в Java - PullRequest
1 голос
/ 16 апреля 2019

У меня есть этот код, чтобы получить процент:

final BigDecimal price = BigDecimal.valueOf(215).setScale(2, BigDecimal.ROUND_HALF_EVEN);
final BigDecimal daysOfThisReservation = BigDecimal.valueOf(3).setScale(2, BigDecimal.ROUND_HALF_EVEN);

final BigDecimal dayPrice = price.divide(daysOfThisReservation, BigDecimal.ROUND_HALF_EVEN).setScale(2, BigDecimal.ROUND_HALF_EVEN);

System.out.println(dayPrice); //71.67
System.out.println(dayPrice.multiply(daysOfThisReservation).setScale(2, BigDecimal.ROUND_HALF_EVEN)); //215.01

У меня есть резервирование, которое стоит 215,00 $, это резервирование имеет 3 в день, поэтому цена составляет 71,67 $.

ЕслиЯ пытаюсь получить исходное значение снова, у меня есть некоторые проблемы с округлением, 71,67 * 3 = 215,01

Как решить эту проблему?

Ответы [ 3 ]

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

Мне кажется, что проблема здесь не в том, чтобы отбросить первоначальную цену, а в том, чтобы отбросить ценную информацию путем усечения дробных значений до двух десятичных знаков.Если бы вы сохранили еще одно десятичное число, у вас не возникло бы этой проблемы.

Вот пример, в котором сохраняются 6 знаков точности, чтобы обеспечить достаточную точность для сотен операций над значениями, для которых в конечном итоге мне нужны только двазначащие десятичные знаки.У вас никогда не возникнет проблем с округлением до 6 знаков после запятой, если в конце вы заботитесь только о двух местах.

Этот код сохраняет 6 знаков, кроме случаев, когда вы печатаете цену за один день, после чего он округляется до двух знаков.

final BigDecimal price = BigDecimal.valueOf(215).setScale(6, BigDecimal.ROUND_HALF_EVEN);
final BigDecimal daysOfThisReservation = BigDecimal.valueOf(3).setScale(6, BigDecimal.ROUND_HALF_EVEN);

final BigDecimal dayPrice = price.divide(daysOfThisReservation, BigDecimal.ROUND_HALF_EVEN).setScale(6, BigDecimal.ROUND_HALF_EVEN);

System.out.println(dayPrice.setScale(2, BigDecimal.ROUND_HALF_EVEN));
System.out.println(dayPrice.multiply(daysOfThisReservation).setScale(2, BigDecimal.ROUND_HALF_EVEN)); //215.01

Результат:

71.67
215.00
2 голосов
/ 16 апреля 2019

Давайте посмотрим на это так.Память и общение дешевы.

BigDecimal totalPrice = new BigDecimal(double 215.00);
int numNight = 3;
BigDecimal perNightPrice = totalPrice
    .divide(new BigDecimal(int numNight), BigDecimal.ROUND_HALF_EVEN)
    .setScale(2, BigDecimal.ROUND_HALF_EVEN);

На данный момент у вас есть три переменные.Учитывая, что память (основной ОЗУ и вторичный диск / БД) и связь дешевы, вы можете просто сохранить переменную totalPrice.Вам не нужно перепроектировать его из perNightPrice и numNight.

Я был в подобных ситуациях раньше.Мы просто меняем определение API и / или таблицы данных, чтобы позволить нам сохранить еще один фрагмент данных (если только вы не удалите память для memroy в Lunar-Lander - что я сомневаюсь, что это так, поскольку Lunar-Lander не рассчитывает цены на отели),

1 голос
/ 16 апреля 2019

Можно улучшить с определенной точностью?

final BigDecimal price = BigDecimal.valueOf(215).setScale(10, BigDecimal.ROUND_HALF_EVEN);
final BigDecimal daysOfThisReservation = BigDecimal.valueOf(3).setScale(10, BigDecimal.ROUND_HALF_EVEN);
...