Using a series to calculate pi in Python

Question:

pi/2 = 1 + 1/3 + (1*2) / (3*5) + (1*2*3) / (3*5*7) + ...

Okay, let’s try this again.

I need to write a function that takes the max error as a parameter for the value of pi and returns the calculated value of pi and the number of iterations necessary to get to that point. I can’t use a recursive algorithm.

Thus far I have:

def piEuler (x):
    count = 0.0
    approx = 0.0
    approx2 = 1.0
    error = math.pi/2 - approx2
    while error > x:
        count = count + 1
        approx3 = approx + approx2
        error = math.pi/2 - approx3
        #print error
        approx = approx + approx2
        approx2 = approx2 * count/(count + 2)
        #print approx2
    final = math.pi - error
    return final, count

The issue is that the program is returning a negative value. The error should converge to zero. I need to be able to subtract my error from the accepted value of pi to get an approximate value from the series. What am I doing wrong?

Asked By: Sarah Jane

||

Answers:

This works:

import math

def piEuler(x):

    halfpi    = math.pi / 2.0
    count     = 0
    approx    = 1.0
    divisor   = 1
    numerator = 1
    while True:
        count     += 1
        numerator *= count
        divisor   *= 2*count + 1
        approx    += float(numerator) / float(divisor)
        error      = halfpi - approx

        if error < x:
            return (math.pi - error), count

The basic differences are:

  1. By switching the terminating condition of the loop to a test/break, I can remove the manual calculation of the second term of the series
  2. Careful use of int and float datatypes (this may have been your problem)
  3. Better naming of the variables leads to easier debugging
Answered By: Andrew Alcock

You should try to rewrite the routine such that the smallest term in the sequence, approx2 in your code, has to be greater than error.

Also you have ‘math.pi’ in your last error calculation. Does it have to be math.pi/2 ?

It seems the nature of the error is oscillating also!

Answered By: Arcturus

It looks like you were incorrectly implementing the algorithm. Rather than doing pi/2 = 1 + 1/3 + (1*2)/(3*5) + (1*2*3)/(3*5*7) + ..., it looks like your code is doing pi/2 = 1 + 1/3 + (1*2)/(3*4) + (1*2*3)/(3*4*5) + ....

Since the denominators will end up being smaller, you’ll be increasing the sum by a greater amount, resulting no doubt in an overshoot and consequently a negative error.

The problem lies in this line:

approx2 = approx2 * count/(count + 2)

As you can see, when count is even, count + 2 will be even. An easy fix would be to change this to:

approx2 = approx2 * count/(2 * count + 1)

Here is a example algorithm that works, but uses the relative error between terms rather than the absolute error (wouldn’t want to give everything away 😉 ):

from __future__ import division

def half_pi(max_err=10**-6, max_iter=10000):
    partial_sum = cur_term = 1
    n = 1
    while abs(t) > max_err and n < max_iter:
        cur_term = cur_term * (n / (2 * n + 1))
        partial_sum += cur_term
        n += 1
    return partial_sum, n
Answered By: Joel Cornett

Why not use Python’s generator expression to implement Leibniz formula for π (one liner :)) :

4*sum(pow(-1, k)/(2*k + 1) for k in range (10000))
Answered By: Giri
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.