2014-02-13 2 views
2

C++ (double을 사용하여)에서 부동 소수점 산술에 문제가 있습니다. 그래서 사람들이 보통이 유형을 어떻게 다루는 지 궁금합니다. 문제.C++에서 n 개의 동등한 부분으로 간격 나누기

극좌표로 곡선을 일련의 Point 객체로 나타내려고합니다 (Point는 점의 3D 좌표를 보유하는 클래스입니다). 커브를 나타내는 Point 컬렉션은 Point *의 벡터에 저장됩니다. 내가 표현하고있는 곡선은 함수 r (theta)입니다.이 함수는 제가 계산할 수 있습니다. 이 함수는 [0, PI]에 포함 된 theta의 범위에서 정의됩니다. 저는 PI를 4.0 * atan (1.0)으로 나타내며 double로 저장합니다.

표면을 표현하기 위해 현재 n = 80을 사용하고있는 점의 수 (n + 1)를 지정한 다음 [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 < = thetaF) 요구 사항을 충족시키지 못한다는 것입니다. 사실 루프를 마지막으로 통과 한 후에 세타는 PI보다 약간 큽니다 (PI + 1e-15와 같습니다). 어떻게해야합니까? 함수가 theta> PI에 대해 정의되지 않았습니다. 하나의 아이디어는 델타가 매우 작은 경우 ((theta> PI)와 (theta < (PI + delta)))를 테스트하는 것입니다. 그것이 사실이라면, 나는 theta = PI를 설정하고, 대응하는 Point의 좌표를 얻고 설정하고, 루프를 종료 할 수 있습니다. 이것은 합리적인 문제인 것 같지만, 흥미롭게도 전에 그런 문제에 직면 한 적이 없습니다. 나는 gcc 4.4.2를 사용하고 있었고, 이제 gcc 4.8.2를 사용하고있다. 그것이 문제일까요? 이런 종류의 문제를 처리하는 일반적인 방법은 무엇입니까? 감사!

+0

while 루프는 세그먼트 수만큼 이동할 수 있습니다. thetaF보다 큰 값을 갖는 pts가 잠재적으로 문제를 일으킬 수 있으므로 모든 문제를 해결할 수 있을지 확신하지 못합니다. – m24p

+2

루프에서 dta로 theta를 증가시키지 마십시오. 자신이 속한 세그먼트 번호에서 직접 theta를 계산하십시오. 'theta = theta0 + n * dTheta'. Hppe 도움이되지만 일반적으로 부동 소수점으로 인한 문제는 제거하지 않습니다. – knivil

+0

정확히 입력 할 준비가 된 다음 단계입니다. 그것이 도움이 될지 확실하지 않지만 그것이 내가하려고 노력할 것입니다. – m24p

답변

2

는 공정의 정수를 이용하여, 반복 제어

theta = theta0 + idx*dTheta. 

하여 다음의 값을 계산하는 대안이 경우 단위를 추가하여 부동 소수점 값 (세타)와 범위를 반복 절대로 표시된대로 float을 계산하십시오.

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으로 if 문을 cehck 할 수 있습니다. 모든

+0

이것은 특정 반복 횟수와 질문에 주어진'thetaF'의 값에 대해 작동 할 수 있습니다 만,'theta '가 약간 ** ** 적어지기 때문에 반올림이 일어나지 않는 다른 경우에는 실패 할 것입니다 *보다 더 큰 ** ** 대신에 마지막으로 원하는 반복에서 'thetaF'보다 이 경우 첫 번째 루프는 원하는 반복 횟수 후에 종료되고 다음 코드는 원하지 않는 점을 추가합니다. –

0

첫째 : 당신은 당신이 가지고있는 세그먼트의 수를 알고, 그래서

:-) 벌거 벗은 포인터를 제거하는 대신하면서 블록에서 세타의 값을 사용 :

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

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; 
} 
+0

모든 반복마다 i를 곱할 필요가 없습니다. – pauluss86

+0

예, @ pauluss86, 맞습니다. – 0605002

+0

문제는 'theta'가'dTheta '로 증가시킬 때'thetaF' (PI와 동등)보다 더 크게 끝날뿐만 아니라'PI '를 초과하는 인수에 대해'rOfTheta'가 정의되지 않는다는 것입니다 . 따라서이 코드는 반복 횟수가 정확하지만 인수 값이 부적합한 함수를 호출합니다. –

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

이 :

  • 는 (루프 카운터가 정수로 유지되기 때문에) 반복의 정확한 수,
  • 어떤 오류가 축적되지 않는 생산 (theta 갓마다 계산하기 때문에)
  • 은 최종 반복 (정확하게 (double) i/nSegments이 1이되기 때문에)에서 원하는 값 (물론, PI, π이 아님)을 정확하게 생성합니다.

불행히도 일반적으로 시간이 많이 소요되는 지침 인 부분이 포함되어 있습니다.

는 (루프 카운터도 double 될 수 있으며,이 루프 내부 double까지 캐스팅을 방지 할 수 있습니다. 언제 까지나 정수 값을 사용하는 한,의 산술 정확한 될 것입니다, 당신은 2 53 이상으로 될 때까지 반복)

관련 문제