Непоследовательный логарифм и округление

#java #double #rounding #logarithm #significance

#java #двойной #округление #логарифм #значение

Вопрос:

Недавно, разрабатывая калькулятор для упрощения игры (reactor idle), я столкнулся с одной постоянной проблемой. Проблема заключалась в том, что когда вводимое число в графическом интерфейсе изменялось на число между определенными границами, оно немедленно возвращалось к числу под ним при нажатии enter, иногда это даже повторялось, если вы снова нажимали enter.

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

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

Соответствующие фрагменты кода:

 double insulationMultiplier = 1   insulationPerCell * (insulationUpgrades   1) * INSULATION_HEAT_MODIFIER;
            double upgradeMultiplier = Math.pow(Cell.HEAT_MULTIPLIER, cellUpgrades);
            this.heat = cells * insulationMultiplier * upgradeMultiplier * cell.heat * (1   0x4p-50d); //???
                                                                                        //avoid trouble when calculating cellUpgrades

            this.calculate(START_FROM_HEAT);
  

 double insulationMultiplier = 1   insulationPerCell * (insulationUpgrades   1) * INSULATION_HEAT_MODIFIER; 
            double circulatorMultiplier = circulators ? CIRCULATOR_HEAT_MODIFIER * Math.pow(CIRCULATOR_HEAT_MULTIPLIER, circulatorUpgrades) : 1;

            cellUpgrades = (int) ((Math.log(this.heat) - Math.log(insulationMultiplier * cells * cell.heat)) / Math.log(Cell.HEAT_MULTIPLIER));
  

Как вы можете видеть, я решил проблему, умножив тепло, рассчитанное в первой части, на 1 0x4p-50d , это делается для того, чтобы тепло регулировалось ровно настолько, чтобы вторая часть алгоритма не округляла обновление снова и как можно меньше, чтобы избежать отображения сильно отличающегося значения тепла.

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

Есть ли более строгий, так сказать, способ решения этой проблемы?

Заранее спасибо.

Комментарии:

1. Я предполагаю, что вы не работаете на пределе точности double , если да, то вам следует использовать другую стратегию. Либо используйте BigDecimal, либо используйте формулу, в которой нет этой проблемы.

2. Я предполагаю, что * (1 0x4p-50d) это работает как фактор выдумки для небольшой ошибки представления. Я предлагаю сохранить logOfHeat вместо heat значения.