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

时间:2013-10-06 02:56:07

标签: c++ matlab floating-point

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

#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 ++中有类似的东西吗?

1 个答案:

答案 0 :(得分:3)

捏造比较是错误的使用技巧。即使您将比较“正确”,浮点循环计数器也会累积从迭代到迭代的错误。

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

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

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

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

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

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

最后,虽然这种技术保证了所需的迭代次数,但由于缩放中的舍入误差,在第一次或最后一次迭代中,缩放值可能在理想目标间隔之外很小。如果这对您的应用程序很重要,则必须调整这些迭代中的值。