Error in estimating pi by Taylor expansion - python

I am trying to calculate the value of pi, but there is some semantic error in my logic which I am not able to figure out.
def taylor(precision):
iter = 1
sum = 0
fx = 100
sign = 1
while (abs(fx) > precision):
if not iter % 2 == 0:
print(sign)
sum += ((1 / (iter)) * sign)
my_pi = 4 * (sum)
fx = math.pi - my_pi
iter += 1
sign *= -1
return my_pi
This results in an infinite loop.
I am supposed to use this series and find my_pi to a particular precision:
π/4 = (1/1) - (1/3) + (1/5) - (1/7) + (1/9) - ...
Pretty new to programming, any help would be amazing!

This part here
if not iter % 2 == 0:
means you only sum when the iteration is not an even number, i.e., 1, 3, 5, ....
However, you alternate the sign every iteration, including that of the even iterations.
As a result, you get 1/1 + 1/3 + 1/5 + ....
Instead, try
if not iter % 2 == 0:
print(sign)
sum += ((1 / (iter)) * sign)
sign *= -1 # move the sign assignment here

Related

Need to match exact decimal output Python

The German mathematician Gottfried Leibniz developed the following method to approximate the value of π:
π/4 = 1 - 1/3 + 1/5 - 1/7 + . . .
Write a program that allows the user to specify the number of iterations used in this approximation and that displays the resulting value.
An example of the program input and output is shown below:
Enter the number of iterations: 5
The approximation of pi is 3.3396825396825403
iteration = int(input("Enter the number of iteration: "))
list01 = []
list02 = []
y = 1
for x in range(1, iteration+1):
number = (1.0/y)
list01.append(number)
y += 2.0
#print(number)
for i in range(1, iteration, 2):
neg = list01[i]*-1.0
list02.append(neg)
#print(neg)
comb = (sum(list01)) + (sum(list02)) + (sum(list02))
pi = comb*4.0
print("The approximation of pi is", pi)
With this code for:
1 iteration, output is 4.0 which matches the required output of 4
5 iteration, output is 3.339682539682539 which doesn't match the required output of 3.3396825396825403
10 iteration, output is 3.0418396189294015 which doesn't match the required output of 3.0418396189294032
999 iteration, output is 3.1425936543400352 which doesn't match the required output of 3.142593654340044
"""pure step by step Leibniz idea
'sign'-- sign switcher. If you need the sum of even divisors
summ +1/1 (n=0), +1/5 (n=2), +1/9 (n=4), sign is True.
With each odd divisible, 'sign' changes to False, changing the
sign of the next term, summ -1/3 (n=1), -1/7 (n=3), -1/11 (n=5), etc..
"""
iteration = int(input("n: "))
presumm = 0
div = 1
sign = True
for i in range(iteration):
presumm = presumm + 1 / div if sign else presumm - 1 / div
div += 2
sign = not sign
pi = presumm * 4
print(pi)
# n==5, output: 3.3396825396825403
# n==10, output: 3.0418396189294032
# n==999, output: 3.142593654340044
iterations = int(input("Enter the number of iterations: "))
answer = 0
d = 1
pos = True
for f in range(iterations):
if pos:
answer += 1 / d
pos = False
else:
answer -= 1 / d
pos = True
d += 2
final = 4 * answer
print("The approximation of pi is " + str(final))
For an alternating sum, the "floating point error" should be small as can be starting from the small end:
# π/4 = 1 - 1/3 + 1/5 - 1/7 + ...
def leibniz(n_terms):
""" Return pi as per alternating sum of n_terms odd stem fractions. """
if n_terms <= 0:
return 0
sum = .0
for stem in range(n_terms * 2 - 1, 0, -2):
# print(sum, float(1-(stem&2))/stem)
sum += float(1-(stem&2))/stem
return 4 * sum

Sum of P(n) with a recursive function

How can I compute the sum of P (n) with a recursive function for any depth n.
Here's how you could do it:
def P(n, k = 1, currentSum = 0):
if k > n:
return currentSum
currentSum += 1/k**2 + 1/k**4 + 1/k**6
return P(n, k+1, currentSum)
print(P(3)) # 3.4529535322359397
Is something as simple as:
def P(n):
return n if n < 1 else P(n - 1) + 1/n**2 + 1/n**4 + 1/n**6
satisfactory to your needs?
A proposal for a longer but simpler(I think) solution(with an explanation):
Because of the commutative property(a+b = b+a), you can do things backwards. This means that you can solve this equation backwards and instead of incrementing n by 1, you can start with n and decrement by 1, adding as you go. This turns out to be perfect for recursion, as all you need to do is add the terms(1/n**2 and such) with the function for a slightly smaller number, with a corner case:
def P(n):
if n == 0:
return 0
t1 = n**-2#** is the python syntax for raising powers
t2 = n**-4
t3 = n**-6
sum_of_terms = t1+t2+t3
return sum_of_terms + P(n-1)
print(P(100))
#3.7346498674943076
How it works:(calculating P(3))
1. Start with 1/9 + 1/81 + 1/729
2. Add that to P(2):
a. Start with 1/4 + 1/16 + 1/64
b. Add that to P(1)
i. Start with 1/1 + 1/1 + 1/1
ii. Add that to P(0)
iii. To prevent division by zero, return 0
c. So the sum of that is 3
3. So the sum of that is 3.328125
So the total is 3.4529535322359397
Note: Python's floats only hold so much precision.

sum = (1**2) + (2**2) - (3**2) + (4**2)-,...,+(n**2) program code in python

Write a program to show the sum of (1**2) + (2**2) - (3**2) + (4**2)-,...,+(n**2) program code in python using "for" and "While" loop.
Although I wrote only for + iteration as shown below in code but +,-,+,- iteration is much difficult. Here is my code of + iteration:
nstart = 1
nend = 4
count = 0
Sum = 0
for i in range(nstart,nend+1):
count+=1
d = i**2
Sum = Sum + d
print(count,'**2 = ', d )
print('Sum = ', Sum)
#This program print same as [(1**2,+ 2**2,+ 3**2= 9,+,,,,+n**2 and sum of them)]
Another option: use a sign variable and change it accordingly.
sum = 1**2
sign = 1 #positive
for i in range(2, n+1):
sum += sign * (i ** 2)
sign *= -1 #flip sign
You can do % 2 check to check for odd numbers and set the sign as + or - accordingly:
sum = 0
for i in range(1, n+1):
if i != 1 and i % 2:
sum -= (i ** 2)
else:
sum += (i ** 2)
For n value 4, this outputs 12.

Loading from pickle slow/fails

I'm using Gauss-Legendre integration to calculate an integral. To get the necessary roots of the Legendre polynomials, I have followed steps outlined here and it works. To save me the time of generating the roots for high order polynomials, I have added a try:, except: routine to store and load roots generated on prior runs. However, above some number of roots this becomes very slow. For 20 roots, the loading delay is almost non-existent, for 25 it is noticable (on the order of several seconds) and for 30 roots it does not progress at all. (CPU at 100%, but nothing put out to console, no error message.) Why is that and what can I do better? After all, it should just read a list of floats from a file.
import math
import pickle
def Legendre(position, order):
# calculates the value of the Legendre polynomial of any order at a position
# has to be a separate function because of recursion
if order == 0:
return 1.0
elif order == 1:
return position
else:
return ((2 * order - 1.0) * position * Legendre(position, order - 1) - (order - 1) * Legendre(position,
order - 2)) / float(
order)
def Legendrederivative(position, order):
# calculates the value of the derivative of the Legendre polynomial of any order at a position
if order == 0:
return 0.0
elif order == 1:
return 1.0
else:
return order / (math.pow(position, 2) - 1) * (
position * Legendre(position, order) - Legendre(position, order - 1))
def Legendreroots(order, tolerance=10):
try:
with open('rootsfile' + str(order) + 't' + str(tolerance) + '.txt', 'r+') as filecontents:
roots = pickle.load(filecontents)
return roots
except:
if order == 0 or order == 1:
raise ValueError('No roots possible')
roots = []
for counter in range(1, order + 1):
x = math.cos(math.pi * (counter - 0.25) / (float(order) + 0.5))
iterationcounter = 0
dx = 10 * 10 ^ (-tolerance)
while (abs(dx) > tolerance) and iterationcounter < 1000:
dx = - Legendre(x, order) / Legendrederivative(x, order)
x += dx
iterationcounter += 1
if iterationcounter == 999:
print 'Iteration warning!', dx
roots.append(x)
print 'root' + str(counter) + 'found!'
with open('rootsfile' + str(order) + 't' + str(tolerance) + '.txt', 'w+') as filecontents:
pickle.dump(roots, filecontents)
return roots
roots = Legendreroots(20)
The first two functions are the function definitions of polynomial and its first derivative respectively, third function generates the roots and handles file I/O.

broken memoization code

I have a series of numbers I need to find the sum of. The value of the first iterative operation is 1, the second is 20. Every iteration which follows then uses the previous result in the formula n * (n + 1) / 2, so the third iteration, say i03 = 20 * (20 + 1) / 2, and the fourth, i04 = i03 * (i03 + 1) / 2. This continues until the 20th iteration of i20 = i19 * (i19 + 1) / 2. I want to do this using memoization. This is my code:
def outFun():
def sumFun(squares, total = 0, CONST = 20):
if squares > 2:
total = sumFun(squares - 1) * int((sumFun(squares - 1) + 1) / 2)
elif not squares - 2:
total = CONST
return total
return 1 + sumFun(20)
What am I doing wrong?
Here is how I understand your problem: You have a formula x_n = x_{n-1} * (x_{n-1} + 1)/2 with recursion base defined as x_1 = 20 (or x_2 = 20? Not clear from your description). The most efficient way to solve the recursion is bottom-up approach, when you start with x_1, then calculate x_2, etc. Alternative is to use dynamic programming/memorization:
mem={}
def f(x):
if x == 1: # base case
return 20
if not x in mem: # if we did not calculate it before - calculate
mem[x] = f(x-1) * (f(x-1) +1) / 2
return mem[x] # otherwise return it
print f(1)
print f(2)
print f(3)
prints
20
210
22155
f(20) is a little large to print, so I will print the number of digits in it:
print "number of digits: %s" % len(str(f(20)))
number of digits: 530115
The code took about 9 seconds to run on my desktop:
import timeit
mem={}
print "Execution time: %s" % timeit.Timer("len(str(f(20)))",
setup = "from __main__ import f").timeit(1)
you're calling
sumFun(squares - 1)
twice!
Why not introduce a variable to store the result? Something like:
if squares > 2:
nextResult = sumFun(squares - 1)
total = nextResult * ((nextResult + 1) / 2)

Categories

Resources