我在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。这可能是问题吗?处理这类问题的正常方法是什么?谢谢!
答案 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 迭代。)