While

I'm trying to calculate pi without using for. However when I execute my program it just goes on and on forever. Probably because I'm not using "while" properly but I can't figure it out.

#include <iostream>
#include <iomanip>

using namespace std;
 int main()
 {  
     int x, loop;
     long double pi = 0.0, num = 4.0, denom = 1.0;
        

     cout << setiosflags( ios::fixed | ios::showpoint )
          << "\nterm\t\t pi\n" ;
    
    for (pi = 0; loop <= 240000; pi++){
     while ( pi <= 3.141590 ){
         if ( loop % 2 != 0 )
            pi += num / denom;
         else
             pi -= num / denom;
      
       cout << loop << "\t\t" << setprecision( 6 ) << -pi << '\n';
       denom += 2.0;
       loop++;
       pi;
     }
}  
     cout << endl;
     std::cin.get();
     std::cin.get();

 return 0;
 
}
You're using 'loop' without initialising it, and you've assigned 0 to pi after you've already initialised it. And are you supposed to be incrementing pi in your for loop? Without knowing what kind of numerical method you're trying to use, it's hard to tell exactly what your loop should be doing. Can you explain the exact procedure it's supposed to be using to calculate pi?
Sorry, forgot to remove the for before pasting:
pi = 4- 4/3 + 4/5 - 4/ 7+ 4/9 - 4/11 +.....

to give alternating +/- I us the if else and modulus. I have loop as int. I assumed that each time the sequence ran it would check the 'while' condition before running again. Is it always seeing pi as the 0.0?



#include <iostream>
#include <iomanip>

using namespace std;


 int main()
 {  
     int x, loop;
     long double pi = 0.0, num = 4.0, denom = 1.0;
        

     cout << setiosflags( ios::fixed | ios::showpoint )
          << "\nterm\t\t pi\n" ;
    

     while ( pi <= 3.141590 ){
         if ( loop % 2 != 0 )
            pi += num / denom;
         else
             pi -= num / denom;
      
       cout << loop << "\t\t" << setprecision( 6 ) << -pi << '\n';
       denom += 2.0;
       loop++;
     }
 
     cout << endl;
     std::cin.get();
     std::cin.get();

 return 0;
 
}
I see. But you haven't value initialised the loop variable - declaring it as an int just intialises it to whatever value happened to be in its memory location at the time it was initialised.

Secondly, after the first iteration, the value of your pi variable will be equal to 4.0, which will terminate the loop right away. You really should impose an extra condition on your loop that keeps it running until a minimum number of iterations have been performed. Conditions like the one you have should only be used if you're certain of how the series will behave - if you don't know that it will converge to a value greater than 3.141590, it's not a good idea to use it as a terminating condition for the loop.

Also, I notice you have an unused int called x, and your program is set to print -pi, instead of pi.
You're right that initially it should be higher than pi. I didn't think about that. Can I simply add the condition to the while? So "while (pi <=3.14159 || loop>=5)"

Currently the program runs forever. So even making these changes I have a problem with actually making the process stop where I need it to.

The idea is that I can stop it at 3.141590 and then see how many iterations were required to get there from the loop count.


probably isnt working properly because pi with that formula is negative.. trying to change it now..
Last edited on
This is what I have now but it is still not stopping at 3.141590:

#include <iostream>
#include <iomanip>

using namespace std;


 int main()
 {  
     int loop=0;
     long double pi = 0.0, num = 4.0, x=0,  denom = 1.0;
        

     cout << setiosflags( ios::fixed | ios::showpoint )
          << "\nterm\t\t pi\n" ;
    

     while ( x <= 3.141590 || loop <=370000 ){
         if ( loop % 2 != 0 )
            pi += num / denom;
         else
             pi -= num / denom;
      x = -1 * pi;
       cout << loop << "\t\t" << setprecision( 6 ) << x << '\n';
       denom += 2.0;
       loop++;
       x;
     }
 
     cout << endl;
     std::cin.get();
     std::cin.get();

 return 0;
 
}
You realize this method requires a very large amount of iterations before you get 6 digits worth of accuracy and that doing output on every loop iteration bogs down the speed of the program considerably?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <iomanip>

using namespace std ; 

 int main()
 {  
    unsigned iterations = 0 ;
    long double pi = 0.0 ;

    long double numerator = 4.0 ;
    long double denominator = 1.0 ;
     
     std::cout << "How many iterations would you like to try? " ;
     unsigned max_iterations ;
     std::cin >> max_iterations ;

     std::cout << "How many iterations should we go between outputs? " ;
     unsigned display_iteration ;
     std::cin >> display_iteration ;

     cout << setiosflags( ios::fixed | ios::showpoint )
          << "\nterm\t\t pi\n" ;

     while ( iterations++ < max_iterations )
     {
         pi += numerator / denominator ;

         numerator = -numerator ;
         denominator += 2 ;

         if ( (iterations % display_iteration) == 0 )
             std::cout << iterations << "\t\t" << pi << '\n' ;
     }
}
How many iterations would you like to try? 500000
How many iterations should we go between outputs? 50000

term             pi
50000           3.141573
100000          3.141583
150000          3.141586
200000          3.141588
250000          3.141589
300000          3.141589
350000          3.141590
400000          3.141590
450000          3.141590
500000          3.141591
I think you need to examine the mathematics a bit more closely. Each term of the series you described can be expressed:

a = (-1)n * 4(2n + 1)-n

And pi is the sum of a from n = 0 to n = infinity. You didn't need to introduce an extra variable called x - you could have just changed your if statement to:

if ( loop % 2 == 0 )

Notice the (-1)n term in the expression above - this means each iteration adds or subtracts a value of magnitude 4(2n + 1)-n in alternation. So even though the sequence may converge to 3.141590, it won't approach from one side. Your loop condition:

while ( x <= 3.141590 || loop <=370000 )

expects that it starts below 3.141590, and strictly increases until it reaches that value and the loop terminates. But this isn't how the series actually works - so you need to redesign your loop. Try something like this:

while ( abs(pi - 3.141590) > 0.000001 )

You'll need to include the <cmath> header. This determines the magnitude of the difference between the calculated value and the value you want, and compares it with a tolerance (in this case 0.000001). If it's close enough (from either side), the loop terminates. But it only works if, at some point, the value of pi you're calculating is 3.141590 +/- 0.000001 - and unless you've analysed the series and you know that it converges to 3.141590, there's no guarantee that this condition will ever be true.

If you don't know exactly what it converges to, you should use a method that finds the change in pi between each iteration, and compares that with a tolerance to determine whether to terminate or not. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
double tol = 0.000001;
double cur = 0;
double prev;
int loop = 0;

do {
    prev = cur;
    //   Then calculate cur
    //   Then increment the loop counter, update the denominator,
    //    output to the screen, etc.
} while ( abs(cur - prev) > tol );

cout << "Final value is: " << (cur + prev) / 2 << endl;


It could actually be written a bit more succinctly, you're only adding to/subtracting from cur at each iteration, but this way is nice and clear. Now in each iteration, a variable containing the previously calculated value is updated, at after each iteration, it's used to find the change in cur. As the series converges, this difference becomes smaller, until eventually it is less than or equal to tol. At this point, the loop terminates, and the final value is determined by taking the midpoint of cur and prev. This is a much better way of numerical computation than just expecting it to behave a certain way - in fact, if you know what it will converge to, there's no point running the loop in the first place except to see it happen before your eyes.
Do you notice that cire's solution does not have doubles in the loop expressions?

Doubles & floats are represented by binary fractions, and not all real numbers can be represented exactly.

This causes problems with comparisons.

For this reason, loop expressions should always have integer expressions.

+1 cire

Edit:

I do like jellyfox's idea of using a tolerance, but not in the loop conditional expression.
Last edited on
But isn't that problem overcome by sticking to relational operators and avoiding equality operators? If not, what would be the correct way to implement tolerance checking?
@jellyfox

You are right, you have implemented it correctly - I saw the doubles in the while condition and hit the reply button. I should learn to read properly !!! Cheers.
I think I understand everything you all have suggested and I have implemented some of the changes. I can get the program to actually stop now but not exactly where I want it. So if I set it to "while ( abs(pi - 3.14159) >= 0.000001 )" then it never stops at 3.14159 but at 3.141589 after 273703 iterations. I get that its because of the comparison but I'm really trying to get it to stop at ....9. I've tried a few different things now but I'm consistently off (changing it to pi-3.14160 for instance).

Anyone have another suggestion?


#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;


 int main()
 {  
     int loop=0;
     long double pi = 0.0, num = 4.0, x=0,  denom = 1.0;
        

     cout << setiosflags( ios::fixed | ios::showpoint )
          << "\nterm\t\t pi\n" ;
    

     while ( abs(pi - 3.14159) >= 0.000001 ){
         if ( loop % 2 == 0 )
            pi += num / denom;
         else
             pi -= num / denom;
     
       cout << loop << "\t\t" << setprecision( 6 ) << pi << '\n';
       denom += 2.0;
       loop++;
       pi;
     }
 
     cout << endl;
     std::cin.get();
     std::cin.get();

 return 0;
 
}


Reduce the tolerance, and your answer will be more precise. By the way, you should take Cire's recommendation and make it only output every 10,000 iterations or so, and then once after the loop has finished. Text output is extremely slow compared to the mathematical operations it's doing.
Topic archived. No new replies allowed.