在C ++ Qt Library中有一个函数QRect screenGeometry()
。 QRect
包含int width()
和int height()
个函数。如果我将此函数的结果保存到int
变量,那么除法效果很好,但如果我直接在除法中使用此函数之一,则会产生奇怪的结果:
QRect scr_size = QApplication::desktop()->screenGeometry();
int a = 1280;
int b = 720;
int c = scr_size.width();
int d = scr_size.height();
qDebug() << c; // 1920
qDebug() << d; // 1080
qDebug() << ((float(a) / b) - (float(c) / d)); // 0
qDebug() << ((float(a) / b) - (float(scr_size.width()) / d)); // 1.32455e-08
qDebug() << ((float(a) / b) - (float(c) / scr_size.height())); // 1.32455e-08
qDebug() << ((float(a) / b) - (float(scr_size.width()) / scr_size.height())); // 1.32455e-08
为什么呢?以及如何解决它?
答案 0 :(得分:5)
很明显,正如许多用户所说,你遇到的问题与浮点精度和编译器相关的优化/选择有关如何编码所请求的操作。
密钥在qrect::width()
和qrect::height()
实现中:它们都是内联的,这意味着在预处理器之后的行:
((float(a) / b) - (float(scr_size.width()) / d))
将是:
((float(a) / b) - (float(scr_size.x2-scr_size.x1+1) / d))
让编译器如何以高效的方式编码目标代码中的公式。
这就是为什么在你调用qrect成员函数的所有行中你会得到不同的结果。
供您参考:永远不要将这种差异与0进行比较,这是一个常见错误,请简单检查绝对值(fabs(x)
)是否小于一个非常小的数字(例如0.0001)。
答案 1 :(得分:2)
但int变量和函数有什么区别,返回int?为什么结果不同?
编译器可以自由地做几件事 - 可以自己组合 - 解释价值观的差异:
以任意顺序评估完整表达式,通过必须进行函数调用(即使它最终成为inline
)来决定哪些因素很可能受影响
在更高精度寄存器中更改关于何时将临时结果存储在更高精度寄存器中的决定,例如使用80位CPU寄存器,然后选择不同的时间来回绕到32位float
使用与编译器为您的程序生成的代码中使用的完全不同的优化,CPU指令/寄存器等来评估涉及常量的事物,这意味着从类似1920
的常量移动到函数只在运行时被认为可知的调用会延迟处理并产生完全不同的结果。
答案 2 :(得分:1)
提取两个值并检查0是否与测试均衡相同。
由于十进制 - >二进制转换和精度限制,浮点数的操作不准确,然后是完全相等的错误测试。
可以帮助发现问题的是查看奇怪结果中的 e-08 。 1 * 10 ^ -8 不为0但接近0.更改符号:
1.32455e-08 is 0,0000000132455 which is not 0 but is very near to 0
float 在您的平台中为32位。使用双打可能会使问题消失。这将是危险的,因为它将隐藏错误但不修复错误。