Неправильный результат для разделения двух двойников в сборке релиза - PullRequest
0 голосов
/ 17 апреля 2019

Когда я компилирую свое приложение в режиме Release, я получаю неверный результат деления 40.0 / 5 = 7. При отладочной компиляции это правильно, и результат равен 8

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

//somewhere in code
   double tonnageToRecover = 0.5;//actually, its QDoubleSpinBox->value(), with 0.5 step set. Anyway, the value finally reduces to 0.5 every time
   double tonnagePerArmorPoint = 0.0125;//taken from .json
   int minimumArmorDelta = 5;//taken from .json
...
//palace where the calculations are preformed
    double armorPointsPerHalfTon = tonnageToRecover / tonnagePerArmorPoint;    
    int steps = abs(static_cast<int>(armorPointsPerHalfTon / minimumArmorDelta));
    qDebug() << "armorPointsPerHalfTon = " << armorPointsPerHalfTon;
    qDebug() << "tonnagePerArmorPoint = " << tonnagePerArmorPoint;
    qDebug() << "steps initial = " << steps;
    qDebug() << "minimumArmorDelta = " << minimumArmorDelta;

обе части 1-го деления имеют тип double, tonnageToRecover = 0.5, tonnagePerArmorPoint = 0.0125,результат 40, что нормально. Минимум ArmorDelta равен int = 5

Так почему 40/5 - это не 8 ??

Компилятор - MinGW 32 5.3.0, из пакета Qt 5.11

Скриншоты: Релиз Отладка

Ответы [ 3 ]

0 голосов
/ 17 апреля 2019

@ Джулиан Я тоже это подозреваю, но как мне преодолеть это препятствие?Попробуем изменить шаги на удвоение, затем снова приведем к int.РЕЗУЛЬТАТ: все еще не работает: /

Я нашел решение, но я не знаю точно, почему оно работает сейчас.Текущий код это:

    double armorPointsPerHalfTon = tonnageToRecover / tonnagePerArmorPoint;
//    int aPHT = (int)armorPointsPerHalfTon;
//    double minDelta = 5.0;//static_cast<double>(minimumArmorDelta);
    QString s(QString::number(abs(armorPointsPerHalfTon / minimumArmorDelta)));
    int steps = abs(armorPointsPerHalfTon / minimumArmorDelta);

#define myqDebug() qDebug() << fixed << qSetRealNumberPrecision(10)
    myqDebug() << "tonnageToRecover = " << tonnageToRecover;
    myqDebug() << "tonnagePerArmorPoint = " << tonnagePerArmorPoint;
    myqDebug() << "armorPointsPerHalfTon = " << armorPointsPerHalfTon;
    //myqDebug() << "aPHT = " << aPHT;//this was 39 in Release, 40 in Debug
    myqDebug() << "steps initial = " << steps;
    myqDebug() << "string version = " << s;
    myqDebug() << "minimumArmorDelta = " << minimumArmorDelta;// << ", minDelta = " << minDelta;
#undef myqDebug

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

0 голосов
/ 18 апреля 2019

Ваша основная проблема в том, что вы усекаете.

Предположим, что арифметика действительного числа даст ответ ровно 8. Арифметика с плавающей запятой даст ответ, очень близкий к 8, но может отличаться от него в любом направлении из-за ошибки округления.Если ответ с плавающей запятой немного больше 8, усечение изменит его на 8. Если оно даже немного меньше 8, усечение изменит его на 7.

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

0 голосов
/ 17 апреля 2019

Полагаю, причина в том, что armorPointsPerHalfTon / minimumArmorDelta может быть не 8, а 7,999999999 в Release-версии. Это значение затем изменяется до 7 через int-cast.

Итак, если версия отладки вычисляет armorPointsPerHalfTon / minimumArmorDelta = 8.0000001, результат будет static_cast<int>(armorPointsPerHalfTon / minimumArmorDelta) = 8.

Неудивительно, что отладка / выпуск дают разные результаты (порядка точности машин), так как в версии выпуска происходит несколько оптимизаций.

РЕДАКТИРОВАТЬ: Если это соответствует вашим требованиям, вы можете просто использовать std::round, чтобы округлить двойное число до ближайшего целого числа, а не усечение десятичных дробей.

...