使用std::llround将float转为long long int的精度异常问题咨询
问题描述
尝试用std::llround将float类型值转换为long long int时出现精度偏差,代码如下:
#include <iostream> int main() { float value = 123456.0f; value *= 1.0E+6f; std::cout << value << std::endl; // 1.23456e+11 std::cout << "after rounding: " << std::llround(value) << std::endl; // 123455995904 return 0; }
输出的float值显示为1.23456e+11,但std::llround转换后得到123455995904,预期结果应为123456000000。
而直接对double类型值执行舍入操作:
std::cout << "rounding double: " << std::llround(123456000000.0) << std::endl;
能得到预期的123456000000。
(运行环境:Windows 10 + Visual Studio 2019)
问题原因与解决方法
原因分析
这不是溢出问题,而是**float类型的精度限制**导致的:
- 标准
float是单精度浮点数,仅拥有24位有效二进制位(对应约7-8位十进制有效数字)。 - 目标值
123456000000有12位十进制数字,远超float的精度范围。123456.0f * 1.0E+6f计算后,float无法精确存储123456000000,实际存储的是一个近似值(对应整数123455995904),因此std::llround处理的是这个近似值,自然得不到预期结果。 double类型拥有53位有效二进制位(对应约15-17位十进制有效数字),足以精确存储123456000000,所以直接用double处理能得到正确结果。
解决方案
有两种可靠的解决方式:
- 方式一:全程使用
double类型替代float
将变量类型改为double,计算与舍入均基于double执行,修改后代码如下:#include <iostream> int main() { double value = 123456.0; value *= 1.0E+6; std::cout << value << std::endl; // 1.23456e+11 std::cout << "after rounding: " << std::llround(value) << std::endl; // 123456000000 return 0; } - 方式二:舍入前转换为
double类型
如果必须保留float变量,在调用std::llround时先将float转换为double,利用double的高精度完成舍入:std::cout << "after rounding: " << std::llround(static_cast<double>(value)) << std::endl;
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

