在C++中将一个区间分成n个相等的部分
Dividing an interval into n equal parts in C++
我在c++中遇到了一个从未遇到过的浮点运算问题(使用doubles),所以我想知道人们通常是如何处理这类问题的。
我试图将极坐标中的曲线表示为一系列点对象(点只是一个在三维中保存点坐标的类)。表示曲线的点集合存储在(点*的)向量中。我所代表的曲线是一个函数r(θ),我可以计算它。该函数定义在[0,PI]中包含的θ范围内。我将PI表示为4.0*atan(1.0),并将其存储为双精度。
为了表示曲面,我指定了所需数量的点(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(θ)是计算r(θ)的函数。现在的问题是,最后一点不知何故不满足最后一次进入循环的(theta<=thetaF)要求。实际上,在最后一次通过循环之后,θ比PI稍微大一点(就像PI+1e-15)。我该如何处理?没有为theta>PI定义函数。一个想法是只测试(θ>PI)和(θ<(PI+delta)),其中delta非常小。如果这是真的,我可以设置θ=PI,获取并设置相应点的坐标,然后退出循环。这似乎是一个合理的问题,但有趣的是,我以前从未遇到过这样的问题。我一直在使用gcc 4.4.2,现在我使用的是gcc 4.8.2。这可能是问题所在吗?处理这种问题的正常方法是什么?谢谢
如果您可以通过计算下一个值,则永远不要通过添加增量来迭代具有浮点值(theta)的范围
theta = theta0 + idx*dTheta.
使用整数步数来控制迭代,并按指示计算浮点值。
如果dTheta与整个间隔相比很小,则会累积错误。
您不能插入范围[theta0,thetaF]的最后一个计算值。这个值实际上是θ=θ0+n*(dTheta+误差)。跳过上次计算的值,改为使用taF。
我可以尝试的:
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
来cehck if语句,只需进行实验,看看哪一个能产生更好的结果。
如果您知道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;
}
首先:去掉裸指针:-)
你知道你有多少段,所以不要在while块中使用θ的值:
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);
for (int i = 0; i < nSegments; ++i)
{
theta = (double) i / nSegments * PI;
…
}
此:
- 产生正确的迭代次数(因为循环计数器保持为整数)
- 不累积任何误差(因为
theta
每次都是新计算的),并且 - 在最终迭代中产生精确的期望值(好吧,
PI
,而不是π)(因为(double) i / nSegments
将恰好是一)
不幸的是,它包含一个除法,这通常是一个耗时的指令。
(循环计数器也可以是double
,这将避免循环内从转换为double
。只要使用整数值,它的算术运算就会精确,直到迭代次数超过2次。)
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 在c++中用vector填充一个简单的动态数组
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 预处理器:插入结构名称中的前一个行号
- 我在c++代码中生成了一个运行时#3异常
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 从链接列表c++中删除一个项目
- 告诉一个 const char 数组,除了编译时 C 样式的字符串外,它不以 '