Qt qreal计算错误

Qt qreal calculates wrong

本文关键字:错误 计算 qreal Qt      更新时间:2023-10-16

我想用QSpinBox编辑QGraphicsItem的不透明度。QSpinBox给了我值57,我用它来设置项目的不透明度。 然后我从项目中恢复了更改的不透明度,并想填充QSpinBox.但是设置框的值会导致错误。

qDebug() << (int)(qreal)(0.57 * 100.0);

产出56

这是一个已知的错误吗? 有解决方法吗?

原因

不要依赖浮点数的精度,因为它的计算不准确。您可以在此处或此处阅读有关此问题的更多信息。

示范

如果使用qSetRealNumberPrecision为输出设置更高的精度,您将看到问题的实际根源 –0.57 * 100.0的结果不是精确57,而是类似于 56.999999999999992895:

qDebug() << qSetRealNumberPrecision(20) << 0.57 * 100.0;

溶液

因此,最好简单地将数字四舍五入到最接近的整数,而不是转换为int只是省略分数

qDebug() << qRound(0.57 * 100.0);

适合尾数的整数在浮点中具有精确的表示形式,因此static_cast<qreal>(100.0) == 100始终成立并表示为100*2^0

具有形式分母的有理数2^-n只要分子适合尾数,在浮点中也有精确的表示,因此例如 只要编译器不使用脑死亡十进制到浮点转换函数,static_cast<qreal>(0.25*4) == 1就成立。当大多数编译器解析代码时,它们会将0.254转换为浮点表示形式,然后执行乘法以获取常量表达式的值。

但是static_cast<qreal>(0.57)没有表示为m*2^-n,整数m,n足够小,并且必然表示得不精确。它可以表示为小于或大于0.57。 因此,当您将其乘以100时,它可以略小于57- 在您的情况下。

最简单的解决方法是避免往返:将不透明度作为整数存储在任何地方,并且仅在更改值时从整数转换为浮点数。换句话说,永远不要使用setOpacity()方法,而永远不要使用opacity()方法。使用项目的数据属性存储整数值不透明度:

void setOpacity(QGraphicsItem * item, int opacity) {
item->setData(kOpacity, opacity);
item->setOpacity(opacity / 100.0);
}
void getOpacity(QGraphicsItem * item) {
auto data = item->data(kOpacity);
if (! data.isNull())
return data.toInt();
int opacity = round(item->opacity() * 100.0);
setOpacity(item, opacity);
return opacity;
}

我找到了一个临时解决方案,但我对此不满意。

qDebug() << "qreal" << (int)(qreal)(0.57 * 100.0);
qDebug() << "double" << (int)(double)(0.57 * 100.0);
qDebug() << "float" << (int)(float)(0.57 * 100.0);

输出: Qreal 56, 双56, 浮点数 57