使用std :: floor的表观不一致

时间:2015-05-27 14:16:56

标签: c++ std floor

使用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似乎输出比我预期的小十位的值。

有没有人见过类似的东西?

3 个答案:

答案 0 :(得分:1)

您看到的原因是您的示例中的某些值(例如0.010.29)无法使用floatdouble完全表示。

如果您使用许多有效数字打印结果,您可以更好地了解正在发生的事情:

cout << fixed << setprecision(15) << (value / hundredth) << endl;

value0.29时,此prints

28.999999999999996

此数字非常接近29,但floor无论如何都会将其截断为28。

解决此问题的一种方法是将epsilon添加到除法结果中:

return hundredth * std::floor( value / hundredth + numeric_limits<double>::epsilon());

答案 1 :(得分:0)

您的每股盈利价值是多少?我总是使用EPS值 首先检查我的计算是否错误或计算机是否缺乏精确度:

http://www.cplusplus.com/reference/cfloat/

答案 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() );
}