문제
또 다른 C ++ 운동을하고 있습니다. 무한 시리즈에서 PI의 값을 계산해야합니다.
PI = 4-4/3 + 4/5 - 4/7 + 4/9 -4/11 +. . .
이 시리즈의 첫 1,000 항 각각 후에 프로그램은 PI의 대략적인 값을 인쇄해야합니다. 내 코드는 다음과 같습니다.
#include <iostream>
using namespace std;
int main()
{
double pi=0.0;
int counter=1;
for (int i=1;;i+=2)//infinite loop, should "break" when pi=3.14159
{
double a=4.0;
double b=0.0;
b=a/static_cast<double>(i);
if(counter%2==0)
pi-=b;
else
pi+=b;
if(i%1000==0)//should print pi value after 1000 terms,but it doesn't
cout<<pi<<endl;
if(pi==3.14159)//this if statement doesn't work as well
break;
counter++;
}
return 0;
}
오류와 경고없이 컴파일하지만 실행 후 빈 콘솔 창만 나타납니다. "if (i%1000 == 0)”라인을 제거하면 모든 PI 값이 실행되고 인쇄되는 것을 볼 수 있지만 중지되지 않으므로 두 번째 if 문도 작동하지 않습니다. 무엇을 해야할지 잘 모르겠습니다. 나는 그것이 아마도 간단한 논리적 오류라고 가정합니다.
해결책
글쎄, 나는 당신의 카운터가 i = 1에서 실행되면 2의 증분으로 2의 증분으로 절대 = 0이되지 않습니다. 따라서 나는 항상 홀수이며 결코 1000의 배수가되지 않을 것입니다.
결코 끝나지 않는 이유는 알고리즘이 정확히 3.14157로 수렴하지 않기 때문입니다. 근사치 또는 근사치 이상의 정밀도가 될 것입니다. "주어진 델타 내에서 3.14157의 경우"라고 말하고 싶습니다.
if (fabs(pi - 3.14157) < 0.001)
break
또는 비슷한 것, 그러나 "닫기"에 대해 멈추기 전에 가고 싶어합니다.
다른 팁
당신이 1에서 시작하고 2로 증가하기 때문에, 나는 항상 홀수이므로, 나는 % 1000은 결코 0이 아닙니다.
당신은 둘 이상의 문제가 있습니다.
A. I%1000 == 0은 홀수 만 반복하기 때문에 결코 사실이 아닙니다.
B. pi == 3.14159 : 부동 소수점 번호가 표시되기 때문에 이중 값을 비교할 수 없습니다 (다른 질문에서 여기에서 읽을 수 있음). 작동하려면 다른 방식으로 값을 비교해야합니다. 한 가지 방법은 서로를 빼고 절대 결과가 0.0000001보다 낮는지 확인하는 것입니다.
- 부동 소수점 정밀 문제가 있습니다. 노력하다
if(abs(pi - 3.14159) < 0.000005)
. i%1000
결코 0이 아닙니다i
항상 이상합니다.
그렇지 않아야합니다.
if (counter%1000==0)
나는 1에서 시작한 다음 2로 증가합니다. 그러므로 나는 항상 홀수이며 결코 1000의 배수가되지 않기 때문에 (i % 1000 == 0)가 절대 지나치지 않는 이유입니다.
플로트 정밀 문제로 인해 플로트를 직접 비교하는 것은 작동하지 않습니다. 값의 차이가 충분히 가깝다는 것을 비교해야합니다.
pi = 4-4/3 + 4/5 - 4/7 + 4/9 -4/11 + ...
일반화
pi = σ나=0∞ (-1)나 4 / (2나+1)
각 용어에 대한 더 깨끗한 접근 방식을 제공합니다. 그만큼 나'Th 용어는 다음과 같이 제공됩니다.
double term = pow(-1,i%2) * 4 / (2*i+1);
어디 나= 0,1,2, ..., n
따라서, 우리의 루프는 약간의 반복을 감안할 때 상당히 간단 할 수 있습니다.
int N=2000;
double pi=0;
for(int i=0; i<N; i++)
{
double term = pow(-1,i%2) * 4 / (2*(double)i+1);
pi += term;
cout << i << "\t" << pi <<endl;
}
원래 질문은 "프로그램은이 시리즈의 처음 1,000 조에 따라 PI의 대략적인 값을 인쇄해야합니다"라고 언급했습니다. 이것은 3.14159에 도달했는지 여부를 확인할 필요가 없으므로 여기에 포함시키지 않았습니다. 그만큼 pow(-1,i%2)
전화는 피하는 것입니다 if
진술 (느리게)과 큰 합병증을 방지합니다. 나.
다수의 반복 후, PI의 크기와 수정 항의 크기 (-4/25)의 크기의 차이는 너무 작아서 double
,이를 처리하려면 더 높은 정밀 유형이 필요합니다.
기본적으로 ABS는 int 용 ABS 매크로를 사용합니다. 복식의 경우 CMATH 라이브러리를 사용하십시오.
#include <iostream>
#include <cmath>
int main()
{
double pi=0.0;
double a=4.0;
int i = 1;
for (i=1;;i+=2)
{
pi += (1 - 2 * ((i/2)%2)) * a/static_cast<double>(i);
if( std::abs(pi - 3.14159) < 0.000001 )
break;
if (i > 2000) //1k iterations
break;
}
std::cout<<pi<<std::endl;
return 0;
}
수정 된 코드는 다음과 같습니다. 누군가 비슷한 문제가 있다면 미래에 도움이 될 것이라고 생각했습니다.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double pi=0.0;
int counter=1;
for (int i=1;;i+=2)
{
double a=4.0;
double b=0.0;
b=a/static_cast<double>(i);
if(counter%2==0)
pi-=b;
else
pi+=b;
if(counter%1000==0)
cout<<pi<<" "<<counter<<endl;
if (fabs(pi - 3.14159) < 0.000001)
break;
counter++;
}
cout<<pi;
return 0;
}
여기에 더 나은 것이 있습니다.
class pi_1000
{
public:
double doLeibniz( int i ) // Leibniz famous formula for pi, source: Calculus II :)
{
return ( ( pow( -1, i ) ) * 4 ) / ( ( 2 * i ) + 1 );
}
void piCalc()
{
double pi = 4;
int i;
cout << "\npi calculated each iteration from 1 to 1000\n"; //wording was a bit confusing.
//I wasn't sure which one is the right one: 0-1000 or each 1000th.
for( i = 1; i < 1000; i++ )
{
pi = pi + doLeibniz( i );
cout << fixed << setprecision( 5 ) << pi << "\t" << i + 1 << "\n";
}
pi = 4;
cout << "\npi calculated each 1000th iteration from 1 to 20000\n";
for( i = 1; i < 21000; i++ )
{
pi = pi + doLeibniz( i );
if( ( ( i - 1 ) % 1000 ) == 0 )
cout << fixed << setprecision( 5 ) << pi << "\t" << i - 1 << "\n";
}
}