2014-02-13 141 views
2

我在使用C++(使用雙精度)的浮點算法時遇到了一個我從未有過的問題,所以我想知道人們通常如何處理這種類型的問題。在C++中將間隔劃分爲n個相等部分

我想在極座標中表示一系列Point對象(Point只是一個保存3D中點座標的類)的曲線。表示曲線的點的集合存儲在一個向量中(Point *)。我表示的曲線是一個函數r(theta),我可以計算。該函數在[0,PI]中包含的theta範圍內定義。我代表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(theta)是計算r(θ)的函數。現在問題是最後一點不能滿足最後一次進入循環的(theta < = thetaF)要求。實際上,在最後一次穿過循環之後,θ比PI稍微大一些(就像PI + 1e-15)。我應該如何處理這個問題?該函數沒有爲theta> PI定義。一個想法是隻測試其中delta非常小的((theta> PI)和(theta <(PI + delta)))。如果這是真的,我可以設置theta = PI,獲取並設置相應點的座標,然後退出循環。這似乎是一個合理的問題,但有趣的是,我從未遇到過這樣的問題。我一直在使用gcc 4.4.2,現在我正在使用gcc 4.8.2。這可能是問題嗎?處理這類問題的正常方法是什麼?謝謝!

+0

您的while循環可以用於段的數量。不確定這會解決你所有的問題,因爲pts的值大於thetaF可能會導致問題的發生。 – m24p

+2

不要通過循環中的dTheta遞增theta。直接從您所在的段號計算theta,例如。 'theta = theta0 + n * dTheta'。 Hppe它會有所幫助,但不會消除浮點問題。 – knivil

+0

這就是我準備打字的下一個要點。不知道這是否會有所幫助,但這是我的嘗試。 – m24p

回答

2

決不通過加入增量,如果你有計算的下一個值的由

theta = theta0 + idx*dTheta. 

替代使用的步驟的整數數目控制迭代遍歷與浮點值(THETA)的範圍內並按照指示計算浮點數。

如果dTheta與整個間隔相比較小,則會累積錯誤。

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到cehck if語句,只是實驗,並看到它產生更好的效果。

+0

這可能適用於問題中提供的特定迭代次數和'thetaF'的值,但是在其他情況下,如果碰巧正在向下舍入而不是向上舍入,那麼'theta'會稍微少一些* *比最後期望的迭代中的thetaF'而不是**更大**。在這種情況下,第一個循環將在所需的迭代次數後退出,下面的代碼將添加一個不需要的點。 –

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); 
+1

固定。立即downvote有點苛刻。 – pauluss86

+0

投票下降很容易改變。而且,雖然這樣做更好,但它會在迭代過程中累積'theta'中的錯誤。 –

+0

是的,但我寧願讓我的錯誤指出是我可以修復它。 – pauluss86

1

您可能不會插入範圍[theta0,thetaF]的最後計算值。該值實際上是theta = theta0 + n *(dTheta + error)。跳過上一次計算的值,然後使用thetaF。

0

如果您知道將有81個值theta,那麼爲什麼不運行for循環81次?

int i; 
theta = theta0; 

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

每次迭代都不需要與我相乘 – pauluss86

+0

是的,@ pauluss86,對吧。 – 0605002

+0

這個問題表明,當通過用「dTheta」遞增來計算'theta'時,'theta'不僅會比'thetaF'(等於'PI')大,而且'rOfTheta'不會被定義爲超過'PI' 。所以這段代碼得到了正確的迭代計數,但是調用了一個具有不可接受的參數值的函數。 –

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

此:

  • 產生迭代的正確數目(因爲循環計數器被保持爲一個整數),
  • 不積累任何錯誤(因爲theta每次新鮮計算)和
  • 在最後一次迭代中產生正確的期望值(嗯,PI,而不是π)(因爲(double) i/nSegments只是一個)。

不幸的是,它包含一個部門,這通常是一個耗時的指令。

(循環計數器也可以是一個double,這將避免對double循環內的演員。只要整數值被使用,因爲它的運算是準確的,直到你獲得超越2 迭代。)