在C ++中将间隔分成n个相等的部分

时间:2014-02-13 20:30:30

标签: c++ double

我在c ++(使用双打)中遇到浮点运算问题,这是我以前从未遇到过的,所以我想知道人们通常如何处理这类问题。

我试图将极坐标中的曲线表示为一系列Point对象(Point只是一个用3D保持点坐标的类)。表示曲线的点的集合存储在矢量(Point *)中。我所代表的曲线是函数r(theta),我可以计算出来。该函数在[0,PI]中包含的θ范围内定义。我将PI表示为4.0 * atan(1.0),将其存储为double。

为了表示曲面,我指定所需的点数(n + 1),我当前正在使用n = 80,然后我确定将[0,PI]除以80所需的θ间隔间隔(由n + 1 = 81点表示)。所以dTheta = PI / n。 dTheta是双倍的。我接下来为我的点分配坐标。 (参见下面的示例代码。)

double theta0 = 0.0; // Beginning of inteval in theta
double thetaF = PI; // End of interval in theta
double dTheta = (thetaF - theta0)/double(nSegments); // segment width

double theta = theta0; // Initialize theta to start at beginning of inteval

vector<Point*> pts; // Declare a variable to hold the Points.

while (theta <= thetaF)
{
  // Store Point corresponding to current theta and r(theta) in the vector.
  pts.push_back(new Point(theta, rOfTheta(theta), 0.0));

  theta += dTheta; // Increment theta
}

rofTheta(theta)是计算r(theta)的一些函数。现在的问题是,最后一点不能满足最后一次进入循环的(theta&lt; = thetaF)要求。实际上,在最后一次通过循环后,theta略大于PI(就像PI + 1e-15)。我应该怎么处理这个?没有为theta&gt;定义该功能。 PI。一种想法是仅测试((θ> PI)和(θ<(PI + delta))),其中Δ非常小。如果这是真的,我可以设置theta = PI,获取并设置相应Point的坐标,然后退出循环。这似乎是一个合理的问题,但有趣的是我以前从未遇到过这样的问题。我一直在使用gcc 4.4.2,现在我正在使用gcc 4.8.2。这可能是问题吗?处理这类问题的正常方法是什么?谢谢!

6 个答案:

答案 0 :(得分:2)

如果您可以选择计算下一个值,则不要通过添加增量来迭代具有浮点值(theta)的范围

theta = theta0 + idx*dTheta.

使用整数步数控制迭代,并按指示计算浮动。

如果dTheta与整个区间相比较小,则会累积错误。

答案 1 :(得分:1)

您不能插入范围[theta0,thetaF]的计算最后一个值。该值实际上是theta = theta0 + n *(dTheta + error)。跳过最后计算的值并改为使用thetaF。

答案 2 :(得分:0)

我可能会尝试:

while (theta <= thetaF)
{
  // Store Point corresponding to current theta and r(theta) in the vector.
  pts.push_back(new Point(theta, rOfTheta(theta), 0.0));

  theta += dTheta; // Increment theta
}

if (theta >= thetaF) {
  pts.push_back(new Point(thetaF, rOfTheta(thetaF), 0.0));
}

您可能想要使用pts.length() == nSegments检查if语句,只需进行实验,看看哪种效果更好。

答案 3 :(得分:0)

首先:摆脱赤裸的指针: - )

你知道你拥有的段数,所以不要在while块中使用theta的值:

for (auto idx = 0; idx != nSegments - 1; ++idx) {
    // Store Point corresponding to current theta and r(theta) in the vector.
    pts.emplace_back(theta, rOfTheta(theta), 0.0);

    theta += dTheta; // Increment theta
}

pts.emplace_back(thetaF, /* rOfTheta(PI) calculated exactly */, 0.0);

答案 4 :(得分:0)

如果您知道theta有81个值,那么为什么不运行for次循环81次?

int i;
theta = theta0;

for(i = 0; i < nSegments; i++) {
    pts.push_back(new Point(theta, rOfTheta(theta), 0.0));
    theta += dTheta;
}

答案 5 :(得分:0)

for (int i = 0; i < nSegments; ++i)
{
    theta = (double) i / nSegments * PI;
    …
}

此:

  • 产生正确的迭代次数(因为循环计数器保持为整数),
  • 不会累积任何错误(因为每次新计算theta),
  • 在最后一次迭代中产生完全所需的值(嗯,PI,而不是π)(因为(double) i / nSegments将恰好是一个)。

不幸的是,它包含一个分区,这通常是一个耗时的指令。

(循环计数器也可以是double,这将避免在循环内转换为double。只要使用整数值,它的算术就是精确的,直到你超过2 53 迭代。)