在发布版本中划分两个双精度的结果错误



当我在发布模式下编译应用程序时,我得到不正确的除法结果 40.0/5 = 7。在调试编译中它是正确的,结果是 8

我试图投射到双倍,从双倍到整数,没有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;

两个第一师零件都是双精度型,吨位恢复= 0.5,吨位每装甲点= 0.0125,结果是40,这是可以的最小装甲增量为 int = 5

那么为什么 40/5 不是 8??

编译器 - MinGW 32 5.3.0,来自 Qt 5.11 包

截图:释放调试

@Julian我也怀疑这一点,但我如何克服这个障碍?将尝试将步骤更改为双精度,然后再次转换为 int。RESUT:仍然不起作用:/

我找到了一个解决方案,但我不知道它现在为什么有效。当前代码它:

    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 会刷新一些东西,这就是为什么现在计算步骤是正确的。但是,字符串的值"7"不正确。

您的基本问题是您正在截断。

假设实数算术会给出正好 8 的答案。浮点运算将给出非常接近 8 的答案,但由于舍入误差,在任一方向上都可能与它不同。如果浮点答案略大于 8,则截断会将其更改为 8。如果它甚至略小于 8,截断会将其更改为 7。

我建议写一个关于如何避免截断的新问题,并讨论你为什么要这样做。

猜,原因是armorPointsPerHalfTon / minimumArmorDelta在发布版本中可能不是 8,而是实际上是 7.999999999。然后,此值通过 int-cast 更改为 7。

因此,如果调试版本计算armorPointsPerHalfTon / minimumArmorDelta = 8.0000001,则结果为 static_cast<int>(armorPointsPerHalfTon / minimumArmorDelta) = 8

调试/发布产生不同的结果(按机器精度顺序(也就不足为奇了,因为在发布版本中进行了多次优化。

编辑:如果它符合您的要求,您可以使用std::round将双精度四舍五入到最接近的整数,而不是截断小数。

最新更新