user4511836
user4511836

Reputation:

Python Pi approximation

So I have to approximate Pi with following way: 4*(1-1/3+1/5-1/7+1/9-...). Also it should be based on number of iterations. So the function should look like this:

>>> piApprox(1)
4.0
>>> piApprox(10)
3.04183961893
>>> piApprox(300)
3.13825932952

But it works like this:

>>> piApprox(1)
4.0
>>> piApprox(10)
2.8571428571428577
>>> piApprox(300)
2.673322240709928

What am I doing wrong? Here is the code:

def piApprox(num):
    pi=4.0
    k=1.0
    est=1.0
    while 1<num:
        k+=2
        est=est-(1/k)+1/(k+2)
        num=num-1

    return pi*est

Upvotes: 3

Views: 27888

Answers (6)

Yousra ADDALI
Yousra ADDALI

Reputation: 412

def pi_approx(pts: List[List[float]]) -> float:
points_that_satisfy_the_formula = []
for i in pts:
    point = i
    x = point[0]
    y = point[1]
    if math.pow(x, 2) + math.pow(y, 2) <= 1:
        points_that_satisfy_the_formula.append(point)
return 4 * (len(points_that_satisfy_the_formula)/ len(pts))

Upvotes: 0

sjbcode
sjbcode

Reputation: 1

While all of these answers are perfectly good approximations, if you are using the Madhava-Leibniz Series than you should arrive at ,"an approximation of π correct to 11 decimal places as 3.14159265359" within in first 21 terms according to this website: https://en.wikipedia.org/wiki/Approximations_of_%CF%80

Therefore, a more accurate solution could be any variation of this:

import math

def estimate_pi(terms):
    ans = 0.0
    for k in range(terms):
        ans += (-1.0/3.0)**k/(2.0*k+1.0)
    return math.sqrt(12)*ans

print(estimate_pi(21))

Output: 3.141592653595635

Upvotes: 0

Hugh Bothwell
Hugh Bothwell

Reputation: 56714

Here is a slightly simpler version:

def pi_approx(num_terms):
    sign    = 1.                  # +1. or -1.
    pi_by_4 = 1.                  # first term
    for div in range(3, 2 * num_terms, 2):   # 3, 5, 7, ...
        sign     = -sign          # flip sign
        pi_by_4 += sign / div     # add next term
    return 4. * pi_by_4

which gives

>>> for n in [1, 10, 300, 1000, 3000]:
...     print(pi_approx(n))

4.0
3.0418396189294032
3.1382593295155914
3.140592653839794
3.1412593202657186

Upvotes: 0

Dr. Jan-Philip Gehrcke
Dr. Jan-Philip Gehrcke

Reputation: 35836

Important edit: whoever expects this approximation to yield PI -- quote from Wikipedia:

It converges quite slowly, though – after 500,000 terms, it produces only five correct decimal digits of π

Original answer: This is an educational example. You try to use a shortcut and attempt to implement the "oscillating" sign of the summands by handling two steps for k in the same iteration. However, you adjust k only by one step per iteration.

Usually, in math at least, an oscillating sign is achieved with (-1)**i. So, I have chosen this for a more readable implementation:

def pi_approx(num_iterations):
    k = 3.0
    s = 1.0

    for i in range(num_iterations):
        s = s-((1/k) * (-1)**i)
        k += 2

    return 4 * s

As you can see, I have changed your approach a bit, to improve readability. There is no need for you to check for num in a while loop, and there is no particular need for your pi variable. Your est actually is a sum that grows step by step, so why not call it s ("sum" is a built-in keyword in Python). Just multiply the sum with 4 in the end, according to your formula.

Test:

>>> pi_approx(100)
3.1514934010709914

The convergence, however, is not especially good:

>>> pi_approx(100) - math.pi
0.009900747481198291

Your expected output is flaky somehow, because your piApprox(300) (should be 3.13825932952, according to your) is too far away from PI. How did you come up with that? Is that possibly affected by an accumulated numerical error?

Edit

I would not trust the book too much in regard of what the function should return after 10 and 300 iterations. The intermediate result, after 10 steps, should be rather free of numerical errors, indeed. There, it actually makes a difference whether you take two steps of k at the same time or not. So this most likely is the difference between my pi_approx(10) and the books'. For 300 iterations, numerical error might have severely affected the result in the book. If this is an old book, and they have implemented their example in C, possibly using single precision, then a significant portion of the result may be due to accumulation of numerical error (note: this is a prime example for how bad you can be affected by numerical errors: a repeated sum of small and large values, it does not get worse!).

What counts is that you have looked at the math (the formula for PI), and you have implemented a working Python version of approximating that formula. That was the learning goal of the book, so go ahead and tackle the next problem :-).

Upvotes: 1

Vincent
Vincent

Reputation: 13423

This is what you're computing:

4*(1-1/3+1/5-1/5+1/7-1/7+1/9...)

You can fix it just by adding a k += 2 at the end of your loop:

def piApprox(num):
    pi=4.0
    k=1.0
    est=1.0
    while 1<num:
        k+=2
        est=est-(1/k)+1/(k+2)
        num=num-1
        k+=2
    return pi*est

Also the way you're counting your iterations is wrong since you're adding two elements at the time.

This is a cleaner version that returns the output that you expect for 10 and 300 iterations:

def approximate_pi(rank):
    value = 0
    for k in xrange(1, 2*rank+1, 2):
        sign = -(k % 4 - 2)
        value += float(sign) / k
    return 4 * value

Here is the same code but more compact:

def approximate_pi(rank):
    return 4 * sum(-float(k%4 - 2) / k for k in xrange(1, 2*rank+1, 2))

Upvotes: 2

user4600699
user4600699

Reputation: 1485

def piApprox(num):                                                              
  pi=4.0                                                                      
  k=3.0                                                                       
  est=1.0                                                                     
  while 1<num:                                                                
    est=est-(1/k)+1/(k+2)                                                   
    num=num-1                                                               
    k+=4                                                                    

  return pi*est

Also for real task use math.pi

Upvotes: 0

Related Questions