Hey guys,

I am brand spanking new to C# and am not only wondering about the syntax, but also the logic of how to do this, my professor just threw us to the wolves with this problem and we haven't gone over any of the syntax or anything, I am not a math major so I'm not familiar with the infinite series, nothing explained! And yet it's due on Monday.

The problem is that she wants a C# console program which computes Pi from an infinite series

Pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + ....

She said

"Ask the user the number of decimal places you should compute Pi to and display the number of terms (counting the initial 4) that it takes to compute Pi to that many places. The formula can be used to determine if your approximation is close enough

Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))

Sample Output:
Please enter the number of decimal places to compute to: 2

It requires 200 terms to approximate Pi to 2 decimal places. "

Please help I am completely lost, I need help with logic and help how to program this in C#.

Comments
Good question.

You could observe that Pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + ....
is the same as Pi = 4*(1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + ....)
perhaps this should ring a bell?

What is it actually asking when it says to compute to a certain amount of decimal places? Like in the example the answer is 200 from 2 decimal places, again I was a former music major, not a math person.

Strange, as I see it, you are following some sort of computer class. This is something at least vaguely related to math did you not know that?
All you have to do is calculate a sum with N terms and then multiply this sum by 4. Try to figure out something in C# syntax so we can see your effort. A hint may be

sum = sum + sign / (2 * k + 1);
       approxPi = 4 * sum;

Edited 6 Years Ago by ddanbe: n/a

Is k suppose to be the input from the user? And what is sign for?

Edited 6 Years Ago by songweaver: n/a

Ok I gave it my first shot and very confused:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compute_Pi
{
    class Program
    {
        static void Main(string[] args)
        {
            int sum;
            int sign;
            int approxPi;
            int input;
         
   

            Console.WriteLine("Please enter the number of decimal places to compute to:");

            input = Convert.ToInt32(Console.ReadLine());
            sum = sum + sign / (2 * input + 1);
            approxPi = 4 * sum;

            
            
        }
    }
}

OK, that was fun.

Anyway, what you're going to want to do is loop until you've met your exit condition, which is determined by the formula your teacher gave you.

Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))

Think of it as something like this (in pseudocode)

Obtain required number of decimal places
Declare and initialize all required variables

While condition not met
   is my next term negative or positive?
   if positive
      add 4 / next divisor
   if negative
      subtract 4 / next divisor

   increment next divisor
   change pos/negative indicator for next term
   how many times have i executed so far?
   test exit condition
Loop

Display results

If you do it right, you'll get a program that spits out 200 terms for 2 decimal places, 2000 for 3, 20000 for 4, etc. (At least, that's what I got. Assuming I did it right!)

The program should be relatively short. As in, my first run was not much longer than my pseudocode. Also, your code has ints! Avoid! Integer math will kill you on this.

Edited 6 Years Ago by apegram: n/a

Your effort is appreciated songweaver:), I believe in the long run you are going to end up with a complete solution! Just want to see what you can make of the suggestion made by apegram.

Would you use float or doubles?

I suggest doubles for your calculations, although ints are fine for counters or for the value on your decimal place limitation (the user input).

So do you use the

Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))

and if so where?

Edited 6 Years Ago by songweaver: n/a

So do you use the

Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))

and if so where?

That's what tells you if your Pi approximation is close enough, so yes, you use it. In my pseudocode, it is the loop exit condition that I'm testing.

While condition not met

   ...do the work...

   test exit condition
Loop

Not saying that you have to do it in such a manner. You could consolidate it and test the condition in my While statement, for example. A different loop (example: Do) could test the condition in the Loop statement. The point is that's the criteria you're evaluating your calculation's precision by.

Could you use a for loop, here is what I have

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compute_Pi
{
    class Program
    {
        static void Main(string[] args)
        {
            double sum;
           
            double approxPi;
            double decimalPlaces;
         
   

            Console.WriteLine("Please enter the number of decimal places to compute to:");
           
            decimalPlaces = Convert.ToDouble(Console.ReadLine());
            for (sum=0;sum < decimalPlaces;sum++)
                {
                    

            Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))
            
        }
    }
}

A "for" loop is useful when you know how many times you want to execute the particular section of code. In this case, you go into it having no idea, as that's the value you're actually trying to find. A "do" or a "while" loop would be better.

So would it be like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compute_Pi
{
    class Program
    {
        static void Main(string[] args)
        {
            double sum;
           
            double approxPi;
            double decimalPlaces;
         
   

            Console.WriteLine("Please enter the number of decimal places to compute to:");
           
            decimalPlaces = Convert.ToDouble(Console.ReadLine());
            while (sum < decimalPlaces)
                {
                    

            Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))
            
        }
    }
}

Not exactly.

Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces))

This evaluates to true or false. Either the left hand side is less than the right hand or it isn't. That's your exit condition: whether your approxPi value is within the acceptable range. So your loop should be checking this equation.

I realize the Math.Abs.... checks too see if the condition is met then outputs, but is my

while (sum < decimalPlaces)

part correct?

No. decimalPlaces is the variable that simply tells you the number of decimal places you are being held accountable for. If decimalPlaces is 2, you are responsible for approximate accuracy out to the hundredths (0.00) of the value. If 3, then the thousandths. Also, you don't need the sum variable, per se, as that particular function is supposed to be served by approxPi variable in the equation.

Edited 6 Years Ago by apegram: n/a

Comments
You are doing a great job:)

(0.5 * Math.Pow(0.1, decimalPlaces) evaluates to 0.005 if decimalPlaces is 2 and to 0.0005 if decimalPlaces is 3 and so on.
You calculate : 0.5* 1/(10^decimalPlaces)

Let's assume
decimalPlaces = 2;
PI = 3.14159265...
approxPi = 3.13659268... (Will be after 200 iterations)
The condition Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces)) evaluates to:
Math.Abs(3.14159265... - 3.13659268...) < 0.005
The reason we take the absolute value is that our substraction can evaluate to a negative number and would always be smaller than 0.005. (For example, your first calculation in the loop of approxPi is equal to 4.0.)
This finally becomes 0.00499997...< 0.005 and this evaluates to true.
Use this condition in an if statement.

if ( Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces)) )
{
//do something if true
}
// we come here if the condition evaluates false

Edited 6 Years Ago by ddanbe: n/a

I have worked and worked to get the logic right but it seems I am getting errors with the approxPi and decimalPlaces, saying that approxPi the operator "-" can't be used and decimalPlaces "the best overload for Math.Pow is (double, double). What am I doing wrong and tell me if you see anything else wrong that will cause it not to work.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compute_Pi
{
    class Program
    {
        static void Main(string[] args)
        {
            int NumberOfTerms = 0;

            decimal approxPi;
            decimal decimalPlaces;
            int divisor = 1;
            bool addFlag = true;



            Console.WriteLine("Please enter the number of decimal places to compute to:");

            decimalPlaces = Convert.ToDecimal(Console.ReadLine());
            while (Math.Abs(Math.PI - approxPi) > (0.5 * Math.Pow(0.1, decimalPlaces)))
            {
                if (addFlag == true)
                {
                    approxPi = approxPi + 4 / divisor;
                    addFlag = false;
                }
                else
                {
                    approxPi = approxPi - 4 / divisor;
                    addFlag = true;
                }
                divisor = divisor + 2;
                NumberOfTerms = NumberOfTerms + 1;

            }
            Console.WriteLine("It requires ", NumberOfTerms, " terms to approximate Pi to", decimalPlaces, " decimal places.");
        }
    }

}

Your current code is close to being like what I came up with, good effort!

I haven't tried running yours (or fixing the errors), but I think you should change a couple of variable types and give it another try.

approxPi => double
decimalPlaces => int
divisor => double

Also, your output where you indicate the number of terms should be tweaked.

// take your pick

Console.WriteLine("It requires {0} terms to approximate Pi to {1} decimal places.", NumberOfTerms, decimalPlaces);

Console.WriteLine("It requires " + NumberOfTerms.ToString() + " terms to approximate Pi to " + decimalPlaces.ToString() + " decimal places.");
Comments
Was extremely helpful!

He man! Good work so far! I like the way you handled the divisor and changing + - sign.:)
A few remarks, above those of apegram:
decimal is a special data type mostly used in the financial world, you should use a double type here. But I admit decimal places and decimal can get confusing...

approxPi is not initialised the first time you use it!
So make the init like this : double approxPi = 0.0;

divisor should also be a double in your code you are using integer division! C# thinks if you are dividing two integers the / sign is like the DIV word in some other laguages.
So 5/2 gives 2
5/2.0 gives 2.5

Succes, you are almost there!

Edited 6 Years Ago by ddanbe: n/a

Comments
Was very helpful!

Thanks, I hope you learned a lot!
This is what I came up with, if me and I guess apegram also has a solution, would have given this after your first post you would not have learned that much.
So for what it's worth:

class Program
    {
        static void Main(string[] args)
        {           
            // Pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + ....
            // this is a slow iteration!
            const int cMaxIterations = 500000;
            
            double approxPi = 0.0; // initial approximation of PI
            double sum = 0.0; // sum to compute
            double sign = 1.0; // sign of the next term of our sum
            int decimalPlaces = 2; // Make an input routine with Console.ReadLine
            // I hate doing it this way, because normally there is a lot of checking to do
            // But if you don't make any typing mistakes and you know what you are doing use
            // (as you did) decimalPlaces = Convert.ToInt32(Console.ReadLine());

            for (int k = 0; k < cMaxIterations; k++) 
            {
                sum = sum + sign / (2 * k + 1);
                approxPi = 4 * sum;
                sign = -sign; // change sign for the next term
                if (Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces)))
                {
                    Console.WriteLine("Correct decimal places: {0}", decimalPlaces);
                    Console.WriteLine("Correct Pi: {0}", Math.PI);
                    Console.WriteLine("Pi calculated = {0} , number of iterations = {1}", approxPi, k+1);
                    break; //leave the for loop
                }
                if (k == cMaxIterations - 1) Console.WriteLine("To much iterations for me!");
            }
            Console.ReadKey();
        }
    }

I want to post mine, too!

using System;

namespace DaniWeb
{
    class Program
    {
        static void Main(string[] args)
        {
            bool quit = false;

            while (!quit)
            {
                bool validInput = false;
                int decimalPlaces = 0;

                while (!validInput)
                {
                    Console.Write("Enter the number of decimal places to approximate Pi: ");
                    string input = Console.ReadLine();
                    validInput = int.TryParse(input, out decimalPlaces);
                    if (validInput && decimalPlaces <= 0)
                        validInput = false;
                }

                int countOfTerms = 0;
                double approxPi = SolveForPi(decimalPlaces, out countOfTerms);

                Console.WriteLine("\nIt requires {0} terms to approximate Pi to {1} decimal places.\n", countOfTerms, decimalPlaces);
                Console.WriteLine("Approximate Pi:\t{0}", approxPi);
                Console.WriteLine("Actual Pi:\t{0}\n", Math.PI);
                Console.Write("Press Q to quit: ");
                if (Console.ReadKey().KeyChar.ToString().Equals("Q", StringComparison.InvariantCultureIgnoreCase))
                    quit = true;

                Console.Clear();
            }
        }

        static double SolveForPi(int decimalPlaces, out int countOfTerms)
        {
            double approxPi = 0d;
            bool closeEnough = false;
            bool termIsNegative = false;
            double divisor = 1d;
            countOfTerms = 0;

            while (!closeEnough)
            {
                if (termIsNegative)
                    approxPi -= 4d / divisor;
                else
                    approxPi += 4d / divisor;

                termIsNegative = (!termIsNegative);
                divisor += 2d;
                countOfTerms++;
                closeEnough = Math.Abs(Math.PI - approxPi) < (0.5 * Math.Pow(0.1, decimalPlaces));
            }

            return approxPi;
        }
    }
}

But I am glad, as well, that you figured this one out as well. It's the thinking process that guides learning, not simply copying/pasting code without understanding it.

This question has already been answered. Start a new discussion instead.