Qt(C++)中double值放大百万倍时qRound异常结果求助
qRound计算大数时出现异常的原因与解决办法
问题重现
用户运行以下代码时,最后两条语句得到异常结果:
double nnn = 2678.87; QVariant vvv(2678.87); qDebug() << qRound(nnn*1000.0); //--> 2678870 qDebug() << qRound(nnn*10000.0); //--> 26788700 qDebug() << qRound(nnn*100000.0); //--> 267887000 qDebug() << qRound(nnn*1000000.0); //--> 2147483647 ! qDebug() << qRound(vvv.toDouble()*1000000.0); //--> -2147483648 !!!
另一种写法同样出现异常:
qDebug() << qRound(nnn*1000000); //--> 2147483647 ! qDebug() << qRound(vvv.toDouble()*1000000); //--> -2147483648 !!!
原因分析
- qRound的返回值类型限制:
qRound()的返回值是32位有符号int,其取值范围为 -2147483648 ~ 2147483647。 - 数值溢出:2678.87 × 1000000 = 2678870000,该数值远大于32位
int的最大值2147483647,触发整数溢出:- 当输入值超过
INT_MAX时,qRound()直接返回INT_MAX(2147483647)。 vvv.toDouble()*1000000因浮点数精度误差,溢出后符号位被意外翻转,最终返回INT_MIN(-2147483648)。
- 当输入值超过
- 浮点数精度问题:
double无法精确存储所有十进制小数,2678.87在内存中是近似值,乘以1e6后细微的精度偏差进一步影响了溢出后的结果表现。
解决方法
要处理超出32位int范围的数值,需使用支持更大范围的函数或类型:
- 使用qRound64():该函数返回64位有符号
qint64,取值范围覆盖-9223372036854775808 ~ 9223372036854775807,完全容纳2678870000。修改后代码:double nnn = 2678.87; QVariant vvv(2678.87); qDebug() << qRound64(vvv.toDouble()*1000000.0); //--> 2678870000 - 高精度小数运算:若需避免浮点数精度损失,可使用Qt 5.14+提供的
QDecimal类,它能精确表示十进制小数,同时支持更大范围的数值运算。
内容的提问来源于stack exchange,提问作者Morteza M
相关产品推荐
相关产品推荐

