使用std :: floor时,我注意到一些非常奇怪的东西。我正在ubuntu上编译C ++。我试图将一个双精度放到最接近的百分之一,我正在检查输入值已经四舍五入到最接近百分之一的情况,并且我得到的结果不一致。
我的代码:
double hundredthFloor(double value){
double hundredth = 0.01;
return hundredth * std::floor( value / hundredth);
}
在大多数情况下,它有效,
value = 99.87 gives output 99.87
value = 99.879 gives output 99.87
value = 0.39 gives output 0.39
然而:
value = 0.29 gives value 0.28
value = 0.47 gives value 0.46
我尝试了很多输入值,到目前为止只有0.29和0.47似乎输出比我预期的小十位的值。
有没有人见过类似的东西?
答案 0 :(得分:1)
您看到的原因是您的示例中的某些值(例如0.01
和0.29
)无法使用float
或double
完全表示。
如果您使用许多有效数字打印结果,您可以更好地了解正在发生的事情:
cout << fixed << setprecision(15) << (value / hundredth) << endl;
当value
为0.29
时,此prints
28.999999999999996
此数字非常接近29,但floor
无论如何都会将其截断为28。
解决此问题的一种方法是将epsilon添加到除法结果中:
return hundredth * std::floor( value / hundredth + numeric_limits<double>::epsilon());
答案 1 :(得分:0)
您的每股盈利价值是多少?我总是使用EPS值 首先检查我的计算是否错误或计算机是否缺乏精确度:
答案 2 :(得分:0)
尝试以下方法:
cout.precision(17);
cout << fixed << 0.29 << endl;
cout << hundredthFloor(0.29) << endl;
你会得到类似的东西:
0.28999999999999998
0.28000000000000003
这是因为double
并不总是完全代表十进制数,see this answer for details。这意味着有时候一个数字会比你预期的更多或更少;也不会考虑这一点,因此0.29
将在内部表示为0.28999999...
并向下舍入为0.28
。
一个简单的解决方案是在调用std::floor
之前添加一个非常小的数字,例如numeric_limits<double>::epsilon()
:
double hundredthFloor(double value){
double hundredth = 0.01;
return hundredth * std::floor( value / hundredth + std::numeric_limits<double>::epsilon() );
}