Float四舍五入错误

时间:2017-02-16 20:37:02

标签: c++ floating-point precision

#include<iostream>

long myround(float f)
{
  if (f >= UINT_MAX) return f;
  return f + 0.5f;
}

int main()
{
  f = 8388609.0f;
  std:cout.precision(16);
  std::cout << myround(f) << std::endl;
}

输出:8388610.0

我正在尝试理解输出。下一个浮动数大于 8388609.0是8388610但为什么舍入值不是8388609?

2 个答案:

答案 0 :(得分:1)

如果您将示例更改为使用double,则错误消失。问题是floatdouble更有限,它可以存储有效位数。将0.5添加到您的值只会超出浮点数的精度限制,导致它执行某些舍入。在这种情况下,8388609.0f + 0.5f == 8388610.0f

#include<iostream>

long myround(double f)
{
    if (f >= UINT_MAX) return f;
    return f + 0.5;
}

int main()
{
    double f = 8388609.0;
    std::cout.precision(16);
    std::cout << myround(f) << std::endl;
}

如果您继续为您的号码添加数字,那么double最终也会失败。

编辑: 您可以使用static_assert轻松测试。这在我的平台static_assert(8388609.0f + 0.5f == 8388610.0f, "");上编译。它可能会编译在你的身上。

答案 1 :(得分:1)

IEEE-754定义了几种可能的舍入模式,但在实践中,几乎总是使用的是#34;舍入到最近,与偶数&#34;相关联。这也被称为&#34;银行家的四舍五入&#34;,无论如何都无法辨别。

&#34;甚至连#34;意味着如果浮点计算的待舍入结果恰好在两个可表示数字之间的中间,则舍入将在任何方向上使结果的LSB为零。在你的情况下,8388609.5介于8388609和8388610之间,但只有后者在最后一位有零,所以舍入是向上的。如果您已通过8388610.0,结果将向下舍入;如果你已经通过8388611.0,它将向上舍入。