calculating pi with decimal on python with machin formula - python

I am trying to calculate pi with the Machin formula: http://en.wikipedia.org/wiki/Machin-like_formula.
It works when I do not use python's decimal library to get arbitrary precision (source code: http://pastie.org/9650936) but it only gave like 14 digits (3.14159265358979400417638316866941750049591064453125). I decided I wanted to get arbitrary precision but when I did the code for that, it changed the final value for pi. All I really changed was adding Decimal() for all the values, so I'm wondering what is wrong. Source code:
#!/usr/local/bin/python2.7
from decimal import *
getcontext().prec = 100
pi = Decimal(0)
ctwo = Decimal(239)
cfive = Decimal(5)
inc = Decimal(3)
a = Decimal(1)
epi = Decimal(1)/Decimal(5)
opi = Decimal(1)/Decimal(239)
for a in range(1, 10):
if (a%2 != 0):
epi -= Decimal(1)/Decimal((Decimal(inc)*(Decimal(cfive)**Decimal(inc))))
opi -= Decimal(1)/Decimal((inc*(ctwo**inc)))
inc = inc + Decimal(2)
a = a + Decimal(1)
elif (a%2 == 0):
epi += Decimal(1)/Decimal((inc*(cfive**inc)))
opi += Decimal(1)/Decimal((inc*(ctwo**inc)))
inc = inc + Decimal(2)
a = a + Decimal(1)
pi = Decimal(4)*Decimal((epi)-(opi))
pi = Decimal(4) * pi
print pi
and the value I get is slightly off, (3.091383741564895010542821040108680015248075199241027019420298084548814621985888671367248358277198010)
and I have done some experimenting and haven't been able to find out why it's doing this or how to fix it. Any help would be appreciated! Thanks!

Related

Dynamically change floating point precision in Python

I'm trying to write a program that calculates pi with different accuracies and prints out the number and the time elapsed. I want to print the result with the current accuracy each time. I used print('pi = %*f'%(i, pi)) where i is my current floating point accuracy. This made the program round up the number to the i decimal digit. I'm attaching a picture showing my results running the same algorithm but changing output from:
print (" pi = ", pi, " =with ", i-1, " decimal points accuracy= in: ", (-1)*t, "sec")
to:
print (" pi = %.*f"%(i, pi), " =with ", i-1, " decimal points accuracy= in: ", (-1)*t, "sec")
This is my full code:
import time
accuracy = 4
for i in range(1,accuracy + 1):
pi = 0
prevPi = 1
x = 0
t = time.time()
while abs((pi * 4) - prevPi) > 10**((-1)*(i+1)):
#while x < lim:
prevPi = pi * 4
pi += (((-1)**(x))/(1+(2*x)))
#print(abs((pi * 4) - prevPi))
x += 1
pi *= 4
t -= time.time()
print (" pi = %.*f"%(i, pi), " =with ", i-1, " decimal points accuracy= in: ", (-1)*t, "sec")
How do I print the number with i decimal digits WITHOUT rounding?
You could approach your problem by defining function which truncates your number. That function could take two arguments:
number which you want to truncate,
position, at which it would drop all following values.
def truncate(number, position):
'''Return number with dropped decimal places past specified position.'''
return number - number%(10**position)
For instance if you would want number 3.14 truncated to 3.1, you should call following:
truncate(3.14, -1)
Also I modified your code so it would be simpler and match PEP 8 coding conventions. Therefore now it has increased variable naming clarity and better code formatting.
#!/usr/bin/env python3
'''Module for different pi accuracies calculation time comparison.'''
from time import time
def truncate(number, position):
'''Return number with dropped decimal places past specified position.'''
return number - number%(10**position)
def calculate_pi(accuracy):
'''Return pi with certain floating point accuracy.'''
previous_pi = 0
current_pi = 4
iterator = 1
while abs(current_pi - previous_pi) > 10 ** (accuracy-1):
previous_pi = current_pi
current_pi += 4 * ((-1)**iterator) / (1+(2*iterator))
iterator += 1
return truncate(current_pi, accuracy)
def calculation_speed_comparison(max_accuracy):
'''Print comparison of different accuracy pi calculation time.'''
for current_accuracy in range(max_accuracy+1):
calculation_time = time()
current_pi = calculate_pi(-current_accuracy)
calculation_time -= time()
print('pi = {} with {} decimal points accuracy in {} seconds.'.format(
current_pi, current_accuracy, -calculation_time))
calculation_speed_comparison(4)
Output to this code remains very similar to original one:
pi = 3.0 with 0 decimal points accuracy in 3.266334533691406e-05 seconds.
pi = 3.1 with 1 decimal points accuracy in 0.00016045570373535156 seconds.
pi = 3.14 with 2 decimal points accuracy in 0.0014882087707519531 seconds.
pi = 3.141 with 3 decimal points accuracy in 0.01430201530456543 seconds.
pi = 3.1415 with 4 decimal points accuracy in 0.1466822624206543 seconds.

Python - trying to calculate digits of pi and cannot get past 48 digits after the decimal

I am trying to write a program to calclulate digits of pi using the Nilakantha Series in python. Every time it runs though it will not give me more than 50 decimals. Still learning python so any help is appreciated.
# Program using Nilakantha Series to crunch digits of pi
from math import *
from decimal import *
getcontext().prec = 200 # this is not doing anything
# epsilon is how accurate I want to be to pi
EPSILON = 0.000000000000000000000000000000000000000000000000000001
sum = float(3)
step = 0
i = 2
while abs(pi - sum) >= EPSILON:
step += 1
print (step)
if step % 2 == 1:
sum += 4.0 / (i * (i + 1) * (i + 2))
i += 2
else:
sum -= 4.0 / (i * (i + 1) * (i + 2))
i += 2
print (Decimal(sum))
print (Decimal(pi))
print ("Total itterations: ", step)
print ("Accurate to: ", EPSILON)
You are not using the Decimal class to calculate Pi, but rather the float class. getcontext() affects Decimal, not float.
If you want to use Decimal, modify your code to convert to Decimal before looping. Note that AFAIK, the value of Pi is not available as a decimal in Python, so you need to get the value from someplace else (http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html).

Calculating Pi to the Nth digit

I'm trying to enter in a number and calculate pi to that digit input. I managed to be able to calculate Pi, however no matter what number I type it will still generate the same amount of Pi numbers.
I'm a bit confused at what point it's causing to do that
from math import factorial
from decimal import Decimal, getcontext
# Chudnovsky algorithm for figuring out pi
getcontext().prec=100
pi_input = input('How many digits of pi would you like?')
n = int(pi_input)
def calc(n):
t= Decimal(0)
pi = Decimal(0)
deno= Decimal(0)
for k in range(n):
t = ((-1)**k)*(factorial(6*k))*(13591409+545140134*k)
deno = factorial(3*k)*(factorial(k)**3)*(640320**(3*k))
pi += Decimal(t)/Decimal(deno)
pi = pi * Decimal(12) / Decimal(640320 ** Decimal(1.5))
pi = 1/pi
return pi
print calc(n)
Here is my output
How many digits of pi would you like? 5
3.141592653589793238462643383279502884197169399375105820974944592307816346
94690247717268165239156011
Using the Chudnovsky algorithm, the calculation produces about 14.18 decimal digits per iteration: log10((640320^3)/(24*6*2*6)) ~= 14.18. This can be more clearly seen in the formula for ak / ak-1 as shown on this web page:
https://www.craig-wood.com/nick/articles/pi-chudnovsky
For n = 5, the result has about 70 digits of precision.
I just added round function in the return statement in your code and hope and it works for you as it for me.
from math import factorial
from decimal import Decimal, getcontext
# Chudnovsky algorithm for figuring out pi
getcontext().prec=1000
pi_input = input('How many digits of pi would you like?')
n = int(pi_input)
def cal(n):
t= Decimal(0)
pi = Decimal(0)
deno= Decimal(0)
for k in range(n):
t = ((-1)**k)*(factorial(6*k))*(13591409+545140134*k)
deno = factorial(3*k)*(factorial(k)**3)*(640320**(3*k))
pi += Decimal(t)/Decimal(deno)
pi = pi * Decimal(12) / Decimal(640320 ** Decimal(1.5))
pi = 1/pi
return round(pi,n)
print(cal(n))
you can use "%.nf"to format the output string where n is the number of digits you want to output.
e.g.
import numpy as np
print "%.5f"%(np.pi)
from math import factorial
from decimal import Decimal, getcontext
n = int(input('How many digits of pi would you like?'))
# Chudnovsky algorithm for figuring out pi
getcontext().prec=n+1
def calc(n):
t= Decimal(0)
pi = Decimal(0)
deno= Decimal(0)
k=0
#t = ((-1)**k)*(factorial(6*k))*(13591409+545140134*k)
t=(1)*(factorial(1))*(13591409+545140134*k)
deno = factorial(3*k)*(factorial(k)**3)*(640320**(3*k))
pi += Decimal(t)/Decimal(deno)
pi = pi * Decimal(12) / Decimal(640320 ** Decimal(1.5))
pi = 1/pi
return pi
print (calc(n))
this might be a simple code for understanding
from numpy import *
n = int(input('How many digits of pi after decimal would you like to print'))
print(pi)
#print (" value of pi at {:.4f} is" .format(pi))
print('{pi:0.{precision}f}'.format(pi=pi,precision=n))
this is how I would do it :-)
import math
digits = int(input("to how many digits to you want to round PI?"))
def roundpi(n):
return round(pi,n)
roundpi(digits)
Please try this and let me know if it works for you
import numpy as np
def pi_nth(n):
new_str = ''
for i in range(n+2):
new_str += str(np.pi)[i]
return float(new_str)
I answered the same question the short way using PI from the math module.
from math import pi
print()
nums = int(input("Enter the number of decimals: "))
print("Pi to the {}th number of decimals is %.{}f".format(nums, nums) % (pi))
Output
Enter the number of decimals: 5
Pi to the 5th number of decimals is 3.14159
This is in python 3.8 hope it helps.
#To print the Nth decimal place values of pi
from math import pi
#Receive the input value for number of decimal points of pi needed from user
i=input("Enter the number of decimal places needed in pi")
#Variable to hold the pi value upto nth decimal.Assign it to empty string initially
n_val=""
#Convert the pi value to string
string_pi=str(pi)
x=0
#loop through each literals and add the value to a string variable and then print it
while x<=int(i)+1:
n_val+=string_pi[x]
x=x+1
print(n_val)
from math import pi
num = int(input('Enter the number of decimals: '))
print(f"Pi upto {num}th number is {pi:{1}.{num+1}}")

Can anyone tell me why is my code showing the wrong value of pi?

Here's a picture of my output:
inptTol = float(input("Enter the tolerance: "))
print()
term = 1
divNum = 3
npower = 1
sumPi = 0.0
count = 0
while abs(term) > inptTol:
sumPi += term
term = -term/(divNum * (3**npower))
divNum += 2
npower += 1
count += 1
sumPi = math.sqrt(12) * sumPi
pythonPi = math.pi
approxError = abs (sumPi - pythonPi)
print("The approximate value of pi is %.14e\n" \
" Python's value of pi is %.14e\n"
"The error in the approximation of pi is %.6e\n"
"The number of terms used to calculate the value of pi is %g " %
(sumPi, pythonPi, approxError, count))
These are the values it is is showing:
The approximate value of pi is 3.08770957930231e+00
Python's value of pi is 3.14159265358979e+00
I want it to show me this :
The approximate value of pi is 3.14159265358979
Python's value of pi is 3.14159265358979
I think you're missing signal. Apparently you tried to do this but changing the previous term signal and using it on the next term.
See my code, i tried to do like his. What do you think?
import math
inptTol = float(input("The tolerance: "))
signal = 1.0
term = 1.0
divNum = 3.0
npower = 1.0
sumPi = 0.0
count = 0.0
while inptTol < abs(term):
signal *= -1.0
sumPi += term
term = signal / (divNum * (3.0 ** npower))
divNum += 2.0
npower += 1.0
count += 1.0
sumPi *= math.sqrt(12.0)
pythonPi = math.pi
approxError = abs(sumPi - pythonPi)
print("The approximate value of pi is %.14f\n" \
" Python's value of pi is %.14f\n"
"The error in the approximation of pi is %.6e\n"
"The number of terms used to calculate the value of pi is %g " %
(sumPi, pythonPi, approxError, count))
As for me problem is because you change term value. it has to be 1 or -1 - sign.
My version - I use for loop
import math
terms_number = float(input("Enter terms number: "))
sign = 1
divNum = 1
npower = 0
sumPi = 0.0
count = 0
for x in range(terms_number):
sumPi += sign/(divNum * (3**npower))
# values for next term
sign = -sign
divNum += 2
npower += 1
count += 1
sumPi = math.sqrt(12) * sumPi
pythonPi = math.pi
approxError = abs (sumPi - pythonPi)
print("The approximate value of pi is %.14e\n" \
" Python's value of pi is %.14e\n"
"The error in the approximation of pi is %.6e\n"
"The number of terms used to calculate the value of pi is %g " %
(sumPi, pythonPi, approxError, count))
Result for 7 terms
The approximate value of pi is 3.14167431269884e+00
Python's value of pi is 3.14159265358979e+00
The error in the approximation of pi is 8.165911e-05
The number of terms used to calculate the value of pi is 7
Result for 15 terms
The approximate value of pi is 3.14159265952171e+00
Python's value of pi is 3.14159265358979e+00
The error in the approximation of pi is 5.931921e-09
The number of terms used to calculate the value of pi is 15
EDIT: version with your while loop
import math
inptTol = float(input("Enter the tolerance: "))
term = 1
sign = 1
divNum = 1
npower = 0
sumPi = 0.0
count = 0
while abs(term) > inptTol:
term = sign/(divNum * (3**npower))
sumPi += term
# values for next term
sign = -sign
divNum += 2
npower += 1
count += 1
sumPi = math.sqrt(12) * sumPi
pythonPi = math.pi
approxError = abs (sumPi - pythonPi)
print("The approximate value of pi is %.14e\n" \
" Python's value of pi is %.14e\n"
"The error in the approximation of pi is %.6e\n"
"The number of terms used to calculate the value of pi is %g " %
(sumPi, pythonPi, approxError, count))
Your term calculation is wrong:
term = -term/(divNum * (3**npower))
Say term is currently -1/(3*3). This line won't set term to 1/(5 * 3**2); it'll set term to 1/(3*3) / (5 * 3**2). You're reducing term way more than you're supposed to.
It looks like your trying to define term[i+1] in terms of term[i]. If you change that line to:
term = -term*(divNum-2)/(divNum * 3)
then the recursive definition will produce the appropriate values. This definition will flip the sign, remove the old odd number in the denominator, add the new odd number in the denominator, and add a factor of 3 in the denominator.
You can use this kind of pattern to generate the denominator for the terms in your approximation. I'll let you do the division and summation, and the final multiplication by sqrt(12)
print [(-1)**(i%2)*(3**(i)*(1+i*2)) for i in range(0,10)]
You are using e as the number format which means:
Exponent notation. Prints the number in scientific notation using the letter ‘e’ to indicate the exponent.
If you want fixed point output you can use f:
Fixed point. Displays the number as a fixed-point number.
Other formats/options can be found in the documentation
Found the bug in your code. Each term is calculated using the previous term as the numerator, when really you just want alternating -1 and 1s. Changing the formula for calculating term fixes the issue:
term = ((-1)**npower)/(divNum * (3**npower))
Demo

1000 digits of pi in Python

I have been thinking about this issue and I can't figure it out. Perhaps you can assist me. The problem is my code isn't working to output 1000 digits of pi in the Python coding language.
Here's my code:
def make_pi():
q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
while True:
if 4 * q + r - t < m * t:
yield m
q, r, t, k, m, x = (10*q, 10*(r-m*t), t, k, (10*(3*q+r))//t - 10*m, x)
else:
q, r, t, k, m, x = (q*k, (2*q+r)*x, t*x, k+1, (q*(7*k+2)+r*x)//(t*x), x+2)
digits = make_pi()
pi_list = []
my_array = []
for i in range(1000):
my_array.append(str("hello, I'm an element in an array \n" ))
big_string = "".join(my_array)
print "here is a big string:\n %s" % big_string
I know this code can be fixed to work, but I'm not sure what to fix... The print statement saying here is a big string and the my_array.append(str("hello, im an element in an array \n)) is just a filler for now. I know how all the code is used to work, but like I said before, I can't get it to shoot out that code.
If you don't want to implement your own algorithm, you can use mpmath.
try:
# import version included with old SymPy
from sympy.mpmath import mp
except ImportError:
# import newer version
from mpmath import mp
mp.dps = 1000 # set number of digits
print(mp.pi) # print pi to a thousand places
Reference
Update: Code supports older and newer installations of SymPy (see comment).*
Run this
def make_pi():
q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
for j in range(1000):
if 4 * q + r - t < m * t:
yield m
q, r, t, k, m, x = 10*q, 10*(r-m*t), t, k, (10*(3*q+r))//t - 10*m, x
else:
q, r, t, k, m, x = q*k, (2*q+r)*x, t*x, k+1, (q*(7*k+2)+r*x)//(t*x), x+2
my_array = []
for i in make_pi():
my_array.append(str(i))
my_array = my_array[:1] + ['.'] + my_array[1:]
big_string = "".join(my_array)
print "here is a big string:\n %s" % big_string
And read about yield operator from here:
What does the "yield" keyword do?
Here is the answer:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337
The accepted answer is incorrect, as noted in comments.
The OP's code appears to be based on an implementation of Spigot's algorithm copied from here.
To fix the code per the OP's question (although I renamed the variables and functions to match what they were in the original source), one solution might be:
#!/usr/bin/env python
DIGITS = 1000
def pi_digits(x):
"""Generate x digits of Pi."""
q,r,t,k,n,l = 1,0,1,1,3,3
while x >= 0:
if 4*q+r-t < x*t:
yield n
x -= 1
q,r,t,k,n,l = 10*q, 10*(r-n*t), t, k, (10*(3*q + r))/t-10*n, l
else:
q,r,t,k,n,l = q*k, (2*q+r)*l, t*l, k+1, (q*(7*k+2)+r*l)/(t*l), l+2
digits = [str(n) for n in list(pi_digits(DIGITS))]
print("%s.%s\n" % (digits.pop(0), "".join(digits)))
Also, here is a much faster* implementation, also apparently based on Spigot's algorithm:
#!/usr/bin/env python
DIGITS = 1000
def pi_digits(x):
"""Generate x digits of Pi."""
k,a,b,a1,b1 = 2,4,1,12,4
while x > 0:
p,q,k = k * k, 2 * k + 1, k + 1
a,b,a1,b1 = a1, b1, p*a + q*a1, p*b + q*b1
d,d1 = a/b, a1/b1
while d == d1 and x > 0:
yield int(d)
x -= 1
a,a1 = 10*(a % b), 10*(a1 % b1)
d,d1 = a/b, a1/b1
digits = [str(n) for n in list(pi_digits(DIGITS))]
print("%s.%s\n" % (digits.pop(0), "".join(digits)))
I tested both a few times against this online Pi digit generator.
All credit to this Gist by deeplook.
* Based on testing 10,000 digits, where I got about 7 seconds compared to about 1 second.
For up to 1 million digits of pi use math_pi (note: I am the author of the module)
Install with pip:
pip install math-pi
In Python:
>>> import math_pi
>>> print(math_pi.pi(b=1000))
3.1415926535...
From Fabrice Bellard site: Pi Computation algorithm. Sorry for such a straightforward implementation. 1000 is fast enough (0.1s for me), but 10000 isn't such fast - 71s :-(
import time
from decimal import Decimal, getcontext
def compute(n):
getcontext().prec = n
res = Decimal(0)
for i in range(n):
a = Decimal(1)/(16**i)
b = Decimal(4)/(8*i+1)
c = Decimal(2)/(8*i+4)
d = Decimal(1)/(8*i+5)
e = Decimal(1)/(8*i+6)
r = a*(b-c-d-e)
res += r
return res
if __name__ == "__main__":
t1 = time.time()
res = compute(1000)
dt = time.time()-t1
print(res)
print(dt)
I was solved with bellow formula 5-6 years ago.
Machin-like formula
Wikipedia: https://en.wikipedia.org/wiki/Machin-like_formula
Sorry for the code quality. Variable names can be meaningless.
#-*- coding: utf-8 -*-
# Author: Fatih Mert Doğancan
# Date: 02.12.2014
def arccot(x, u):
sum = ussu = u // x
n = 3
sign = -1
while 1:
ussu = ussu // (x*x)
term = ussu // n
if not term:
break
sum += sign * term
sign = -sign
n += 2
return sum
def pi(basamak):
u = 10**(basamak+10)
pi = 4 * (4*arccot(5,u) - arccot(239,u))
return pi // 10**10
if __name__ == "__main__":
print pi(1000) # 1000
I'm not familiar with your algorithm. Is it an implementation of BBP?
In any case, your make_pi is a generator. Try using it in a for loop:
for digit in make_pi():
print digit
Note that this loop is infinite: make_pi() never throws StopIteration
Here you can check whether your program outputs correct 1000 digits:
http://spoj.com/CONSTANT
Of course you can use diff or tc as well but you'd have to copy these 1000 digits from somewhere and there you just submit your program and check whether the score is bigger than 999.
You can try to print even more digits there and thus get more points. Perhaps you'd enjoy it.
Does this do what you want?
i = 0;
pi_str = ""
for x in make_pi():
pi_str += str(x)
i += 1
if i == 1001:
break
print "pi= %s.%s" % (pi_str[0],pi_str[1:])
Here is a different way I found here --> Python pi calculation? to approximate python based on the Chudnovsky brothers formula for generating Pi which I have sightly modified for my program.
def pifunction():
numberofdigits = int(input("please enter the number of digits of pi that you want to generate"))
getcontext().prec = numberofdigits
def calc(n):
t = Decimal(0)
pi = Decimal(0)
deno = Decimal(0)
k = 0
for k in range(n):
t = (Decimal(-1)**k)*(math.factorial(Decimal(6)*k))*(13591409+545140134*k)
deno = math.factorial(3*k)*(math.factorial(k)**Decimal(3))*(640320**(3*k))
pi += Decimal(t)/Decimal(deno)
pi = pi * Decimal(12)/Decimal(640320**Decimal(1.5))
pi = 1/pi
return str(pi)
print(calc(1))
I hope this helps as you can generate any number of digits of pi that you wish to generate.
wallis formula can get to 3.141592661439964 but a more efficient way is needed to solve this problem.
https://www.youtube.com/watch?v=EZSiQv_G9HM
and now my code
x, y, summing = 2, 3, 4
for count in range (0,100000000):
summing *= (x/y)
x += 2
summing *= (x/y)
y += 2
print (summing)

Categories

Resources