0

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

#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++,并且我在 matlab 中没有问题,因为有 eps 命令。但是在 C/C++ 中有类似的东西吗?

4

1 回答 1

3

捏造比较是使用错误的技术。即使你得到“正确”的比较,浮点循环计数器也会在一次迭代中累积错误。

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

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

然后,在循环内,您可以根据需要缩放计数器:

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

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

Note that dividing by 1000 is more accurate than scaling by .001. Division by 1000 has only one error (in the division). However, since .001 is not exactly representable in binary floating point, multiplying by it has two errors (in the conversion of .001 to floating point and in the multiplication). On the other hand, division is typically a very slow operation, so you might choose the multiplication.

Finally, although this technique guarantees the desired number of iterations, the scaled value might be slight outside the ideal target interval in the first or the last iteration, due to the rounding error in the scaling. If this matters to your application, you must adjust the value in these iterations.

于 2013-10-06T09:20:18.030 回答