如何避免浮点格式错误?实现1.39×10000=13900的解决方案
搞定1.39×10000得到精确13900的问题
兄弟,这个坑我之前踩过!你说的完全对——像1.39这种十进制小数,根本没法用二进制浮点数精确存储,内存里它其实是个无限接近1.39的近似值。乘10000的时候,这点微小误差被放大,结果就不是精确的13900;而乘100000时刚好误差被抵消,凑出了正确值,这真的是巧合而已。
下面给你几个实用的解决办法,按需选择:
方法一:用十进制浮点类型(C++11及以上)
C++有专门处理十进制小数的类型,比如std::decimal::decimal32/decimal64,它们是按十进制规则存储的,能精确表示1.39这种数。不过要注意编译器支持(比如GCC需要开启相关编译选项),示例代码:
#include <decimal/decimal> #include <iostream> int main() { std::decimal::decimal64 num = 1.39DD; auto result = num * 10000; std::cout << static_cast<long long>(result) << std::endl; // 稳稳输出13900 return 0; }
方法二:用整数运算绕开浮点误差
既然1.39是两位小数,直接把它转成整数运算就行,完全避开浮点坑:
#include <iostream> int main() { // 把1.39转成整数139(相当于×100) int num = 139; // 1.39×10000 = 139×(10000/100) = 139×100 int result = num * 100; std::cout << result << std::endl; // 输出13900 return 0; }
如果是从字符串读取的1.39,直接解析成整数部分+小数部分的组合计算,会更稳妥。
方法三:四舍五入修正结果
如果必须用普通double类型,那计算后给结果做个四舍五入,把微小误差修正掉:
#include <iostream> #include <cmath> int main() { double num = 1.39; double result = num * 10000; // 用llround四舍五入到最近整数,比强制转int靠谱 long long rounded_result = std::llround(result); std::cout << rounded_result << std::endl; // 输出13900 return 0; }
这里要提一句:强制类型转换只会截断小数部分,如果结果是13899.999999999998,强转int会得到13899,而llround会正确转成13900。
为啥乘100000能得到正确结果?
其实那也是假象!你可以试试用cout << std::setprecision(15) << (1.39 * 100000),会看到它其实是138999.99999999997之类的数值,只是cout默认输出时自动四舍五入成了整数139000而已。
内容的提问来源于stack exchange,提问作者T M
相关产品推荐
相关产品推荐

