关于C++中的浮点数比较

about float number comparision in C++

本文关键字:浮点数 比较 C++ 关于      更新时间:2023-10-16

>我有一个循环来循环给定的最小和最大范围之间的浮点数,如下所示

#include <iostream>
using namespace std;
void main(void)
{
  for (double x=0.012; x<=0.013; x+=0.001) 
  {
    cout << x << endl;
  }
}

这是非常简单的代码,但正如我在计算机语言中所知,我们需要将两个浮点数与考虑的 EPS 进行比较。因此,上面的代码不起作用(我们希望它从 0.012 循环两次到 0.013,但它只循环一次(。所以我手动将 EPS 添加到上限。

#include <iostream>
using namespace std;
#define EPS 0.0000001
void main(void)
{
  for (double x=0.012; x<=0.013+EPS; x+=0.001) 
  {
    cout << x << endl;
  }
}

它现在有效。但是手动执行此操作看起来很丑陋,因为EPS实际上应该取决于机器。我正在将我的代码从 matlab 移植到 C++ 并且由于有 eps 命令,我在 matlab 中没有问题。但是在 C/C++ 中有这样的东西吗?

捏造比较是错误的技术。即使您的比较"正确",浮点循环计数器也会在迭代之间累积误差。

您可以通过对循环计数器使用精确算法来消除误差累积。它可能仍具有浮点类型,但您使用完全可表示的值,例如:

for (double i = 12; i <= 13; ++i)

然后,在循环中,根据需要缩放计数器:

for (double i = 12; i <= 13; ++i)
{
    double x = i / 1000.;
     …
}

显然,在两次迭代的循环中累积的错误并不多。但是,我希望您的值只是一个例子,在实践中可能会有更长的循环。使用此技术,x的唯一错误是在缩放操作中,因此每次迭代中只有一个错误,而不是每次迭代一个错误。

请注意,除以 1000 比缩放 .001 更准确。除以 1000 只有一个错误(在除法中(。但是,由于 .001 在二进制浮点中不能完全表示,因此乘以它有两个错误(在将 .001 转换为浮点数和乘法中(。另一方面,除法通常是一个非常缓慢的操作,因此您可以选择乘法。

最后,尽管此技术保证了所需的迭代次数,但由于缩放中的舍入误差,缩放值在第一次或最后一次迭代中可能会略微超出理想目标间隔。如果这对应用程序很重要,则必须在这些迭代中调整值。