Java 8 - любой хороший алгоритм округления, чтобы округлить большое десятичное число и вернуть итоговое значение как 100 - PullRequest
0 голосов
/ 08 мая 2019

В настоящее время я ищу хороший алгоритм, который будет округлять и возвращать общее значение как 100. Тип переменной - BigDecimal.

Я должен вернуть BigDecimal в двухзначном формате, например 10,10

Результат должен выглядеть примерно так:

Список будет иметь

18,56, 20,96, 18,56, 19,16 и 22,75.

Всего 18,56 + 20,96 + 18,56 + 19,16 + 22,75 должно быть 100,00

Округление при выполнении с этими значениями должно быть очень близко к исходному значению. Должно быть максимально точным.

Это будет не единственный сценарий, в котором может быть от 3, 4, 5, 6 до 10 переменных.

Любая помощь будет оценена.

  1. Я сделал округление массива.
  2. добавлены все значения
  3. Проверил разницу
  4. Теперь я планирую перевернуть округленный массив сортировки и вычесть разницу из первого и второго, чтобы она равнялась 100.

Я не совсем уверен, насколько хорош этот алгоритм, но я был бы очень признателен, если у вас есть идея получше.

 @Test
    public void roundDecimalValuesAndCalculateTotalToHundredPercent() {
        BigDecimal no1 = BigDecimal.valueOf(18.562874251497007);
        BigDecimal no2 = BigDecimal.valueOf(20.958083832335326);
        BigDecimal no3 = BigDecimal.valueOf(18.562874251497007);
        BigDecimal no4 = BigDecimal.valueOf(19.161676646706585);
        BigDecimal no5 = BigDecimal.valueOf(22.75449101796407);
        List<BigDecimal> value = Arrays.asList(no1, no2, no3, no4, no5);


        scaleAndPrintList(value);
    }


    private void scaleAndPrintList(List<BigDecimal> list) {
        list.forEach(bigDecimal -> {
            System.out.println("Number is " + bigDecimal + ", ROUND_CEILING - " + bigDecimal.setScale(2, BigDecimal.ROUND_CEILING) + ", ROUND_HALF_UP - " + bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP));
        });

        list = list.stream()
                .map(bigDecimal -> bigDecimal.setScale(2, BigDecimal.ROUND_CEILING)).collect(Collectors.toList());

        final BigDecimal reduce = list.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

        System.out.println("Addition " + reduce);

        // This is the error.
        final BigDecimal difference = BigDecimal.valueOf(100).subtract(reduce);

        System.out.println("Difference - " + difference);
    }

1 Ответ

1 голос
/ 08 мая 2019

Зависит от того, как вы хотите пожертвовать точностью членов. Чтобы сделать это за 1 проход и распределить ошибку по членам, я бы собрал (округлил / отбросил) часть каждого члена и сохранил сумму округленных значений, после чего добавил округленное отклонение предыдущего до следующего перед округлением. Последний член должен быть рассчитан следующим образом: 100 - (summ of prev) - который будет округлен до 2 цифр.

private static void scaleAndPrintList(List<BigDecimal> list) {
    BigDecimal sum = BigDecimal.valueOf(0);
    BigDecimal delta = BigDecimal.valueOf(0);
    for(int i=0;i<list.size()-1;i++) {
        BigDecimal bd = list.get(i);
        BigDecimal res = bd.add(delta).setScale(2,BigDecimal.ROUND_HALF_UP);
        System.out.println("Number " + bd + " => " + res + "   diff: " + bd.subtract(res));
        delta = bd.subtract(res);
        sum = sum.add(res);
    }
    // Last member
    BigDecimal bd = list.get(list.size()-1);
    BigDecimal res = BigDecimal .valueOf(100).subtract(sum);
    System.out.println("Last Number " + bd + " => " + res + "   diff: " + bd.subtract(res));
}

Выход:

Number 18.564474251497007 => 18.56   diff: 0.004474251497007
Number 20.954483832335328 => 20.96   diff: -0.005516167664672
Number 18.562874251497007 => 18.56   diff: 0.002874251497007
Number 19.161676646706585 => 19.16   diff: 0.001676646706585
Last Number 22.75449101796407 => 22.76   diff: -0.00550898203593
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...