我知道常见的方法是乘以10 ^ n然后除以10 ^ n。 round a float with one digit number 但是由于双精度精度问题,我发现上面的解决方案并不能完全适用于我的情况:
0.965 * 0.9 = 0.8685
std::round(0.8685 * 1000) / 1000 = 0.869
// expects it to be 0.869
std::round(0.965 * 0.9 * 1000) / 1000 = 0.868
如果我想直接从0.869
获取std::round(0.965 * 0.9 * 1000) / 1000
,我必须将声明更改为
std::round((0.965 * 0.9 + std::numeric_limits<double>::epsilon()) * 1000) / 1000 = 0.869
是否有更简单的方法进行舍入而不为每次计算添加epsilon
?
编辑:问题是,直觉上std::round(0.965 * 0.9 * 1000) / 1000
的值应为0.869
(因为0.965 * 0.9 = 0.8685
),但它实际上会给0.868
。我想找到常用的方法,用3位小数精度得到精确的数学值。
答案 0 :(得分:7)
这实际上是一个令人惊讶的非平凡问题,除非您的问题仅涉及格式输出,在这种情况下,您可以使用适当的printf
样式格式化程序,或{{ 1}}操纵者。
从根本上说,使用二进制类型的denary舍入没有多大意义。您的具体问题是由于最接近的IEEE754 ostream
到double
0.965
您的第一个停靠点是学习Is floating point math broken?。希望这会说服你添加一个任意的“epsilon”只是将问题转移到其他输入,并且你使用0.96499999999999996891375531049561686813831329345703125
也没有数字理由。
std::numeric_limits<double>::epsilon()
完美地工作,部分原因是整数std::round
的截止点x.5
是二元有理数,因此可以用二进制浮点精确表示。但是,唉,你不能用它来舍入到任意小数点。
如果您愿意忍受偶尔出现的不良后果,那么您目前正在使用的x
成语可能是您最好的选择。
如果您不能忍受任何虚假错误,那么您可能需要使用十进制类型并对其执行舍入功能。见C++ decimal data types
答案 1 :(得分:0)
您可以专门为该计算创建一个新功能:
#include <iostream>
#include <limits>
#include <cmath>
using namespace std;
double roundDec(double var) {
var = round((var + std::numeric_limits<double>::epsilon()) * 1000) / 1000;
return var;
}
int main() {
double var = 0.8685;
cout << roundDec(var);
return 0;
}