Finding the term at which PI has specific value

Viewed 286

I'm a bit stuck calculating the value of π from the infinite series:

π = 4 – 4/3 + 4/5 – 4/7 + 4/9 – 4/11 + ...

The problem have to solve is "Print a table that shows the value of π approximated by computing the first 200,000 terms of this series. How many terms do you have to use before you first get a value that begins with 3.14159?"

I'm not sure if the condition that I'm using for finding this term is correct. Can someone tell me if it's right or not and if not what's the correct way to do this? I suspect it pertains to how Java rounds numbers.

package com.company;

public class Main {

    public static void main(String[] args) {

        double result = 0;
        int j = 1;
        int k = 1; //controls the if part for finding the term
        int term = 0; //variable for term that we're looking for

        for (int i = 1; i <= 200000; i += 1) {

            if ((i % 2) != 0) {
                result += (double) 4 / j; //positive part
                j += 2;
            }
            else {
                result -= (double) 4 / j; //negative part
                j += 2;
            }

            if (k != 0) {

                /* Attempts to detect when result == 3.14159 */

                if (result > 3.14158 && result < 3.14160) { 
                    term = i;
                    k = 0;
                }
            }

            System.out.printf("%f\n", result);
        }

        System.out.println("Term at which pi has value 3.14159: " + term);
    }
}
3 Answers

The Java Math class is your friend. Documentation is here: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html

I would be inclined to do the test using Math.floor(result * 100000) == 314159)

You may also want to include i in your results so you can easily check your answer against the table.

Finally, I would use a boolean rather than an int for the test.

To check is the number begins with 3.14159, you need to check for values great than or equal to that value, and less than 3.14160:

if (result >= 3.14159 && result < 3.14160) {
    ..
}

With that change I get a value for term of 136121, which I've verified elsewhere is the expected answer.

There's no need for any multiplication and rounding operations on the result because the range of precision required (six decimal digits) is far less than that provided by a Java double.

I incorporated @Alnitak's suggestion into code to give you some other ideas how you might optimize it and insights into how the language can be used. I tweaked it a little to iterate an order of magnitude more times and produce one more decimal place of precision. But the limit you're going to bump into with the IEEE 754 floating point math used by most languages is how floating point numbers are represented internally. Many numbers are actually 'not a number', e.g. impossible to represent. So there is rounding. I'm sure NASA has ways around this :-) I'm no mathematician but there are probably papers around that discuss techniques for achieving more precision, outside the scope of your question.

public class Main {

    private final static int MAX_LOOP = 2000000;    
    private static int i = 1;

    public static void main(String[] args) {
        double j = 1.0, result = 0.0;

        for ( ; i < MAX_LOOP; i++, j += 2.0) {

            if ((i % 2) != 0) 
                result += 4.0 / j;
            else
                result -= 4.0 / j;

            if (result >= 3.141592 && result < 3.141593)
                break;

            System.out.println(result);
        }

        if (i < MAX_LOOP)
            System.out.println("Term at which pi has value 3.141592..." + result + " = " + i);
        else
            System.out.println("Couldn't find pi using series with maximum iterations = " + MAX_LOOP);
    }
}
Related