Проблема округления в Java.Почему я не получаю ожидаемых результатов в этом случае? - PullRequest
0 голосов
/ 26 мая 2019

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

Это работает, но есть сбой, из-за которого уравнение пропускает опыт.

Вот код:

private void divideExpAmongstPlayersBasedOnDamageDealt(int exp, Map<Player, Double> damageMap) {
    double totalDamageDealt = 0.0d;

    for (Double value : damageMap.values()) {
        totalDamageDealt += value;
    }

    while (exp > 0 && !damageMap.isEmpty()) {
        Player maxHitterInList = Collections.max(damageMap.entrySet(),
                Comparator.comparingDouble(Map.Entry::getValue)).getKey();

        double damageShare = damageMap.get(maxHitterInList) / totalDamageDealt;
        int expShare = (int) Math.round(exp * damageShare);

        if (expShare == 0)
            break;

        if (maxHitterInList.isOnline()) {
            sendPlayerMessage(maxHitterInList, damageShare, expShare);
            maxHitterInList.giveExp(expShare);
        }

        exp -= expShare;

        damageMap.remove(maxHitterInList);
    }
}

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

Проблема в том, что он пропускает очки, вынуждая меня добавить && !damageMap.isEmpty() к условию while, чтобы избежать исключений. Он всегда печатает проценты точно (сумма складывается до 100).

Я думаю, что это связано с функцией Math.round, хотя я нахожусь в неведении относительно того, как отладить это. Когда я делаю вычисления вручную, они работают.

Пример (это буквально произошло): моб дарует 10 опыта. Игрок1 нанес 57% урона, Игрок2 нанес 43%. Процентные значения печатаются правильно, но Player1 получает 6 EXP, а Player2 получает 2 ?? В прошлый раз я проверял 0.57 * 10 равно 5.7 = 6 и 0.43 * 10 равно 4.3 = 4.

Что мне не хватает? Это связано с функцией округления или с тем, как удваивается работа?

Спасибо

1 Ответ

2 голосов
/ 26 мая 2019

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

Вы написали "В прошлый раз я проверял, что 0,57 * 10 равно 5,7 = 6, а 0,43 * 10 равно 4,3 =4 ", но вы используете формулу

int expShare = (int) Math.round(exp * damageShare);

, и вы обновляете exp для каждой итерации цикла

exp -= expShare;

, что означает для вашего второго игрока expдля 4, а не для 10, как вы предполагали в своем примере, поэтому реальный расчет равен 0,43 * 2 , а округлено до 2

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

...