Obliczenia liczby Pi
-
jacek
12/12/2017
- Programowanie
- 2217 czytań 0 komentarzy
#!/bin/bin/nv python
#-*- coding: utf8 -*-
'''Chudnovsky algorithm
https://en.wikipedia.org/wiki/Chudnovsky_algorithm'''
from decimal import Decimal as Dec, getcontext as gc
def PI(maxK=70, prec=2001, disp=2000): # parameter defaults chosen to gain 1000+ digits within a few seconds
gc().prec = prec
K, M, L, X, S = 6, 1, 13591409, 1, 13591409
for k in range(1, maxK+1):
M = (K**3 - (K<<4)) * M / k**3
L += 545140134
X *= -262537412640768000
S += Dec(M * L) / X
K += 12
pi = 426880 * Dec(10005).sqrt() / S
pi = Dec(str(pi)[:disp]) # drop few digits of precision for accuracy
print("PI(maxK=%d iterations, gc().prec=%d, disp=%d digits) =\n%s" % (maxK, prec, disp, pi))
return pi
Pi = PI()
print("\nFor greater precision and more digits (takes a few extra seconds) - Try")
print("Pi = PI(317,4501,4500)")
print("Pi = PI(353,5022,5020)")
kolejny kod wykorzystuje formułę Machina:
#!/usr/bin/nv python
# -*- coding: utf-8 -*-
'''
Python 2.7.3
Today, computers can be used to calculate millions of digits of pi by using
infinite series formulas. There are several different ways to do this,
but one of the most efficient methods that is relatively straightforward
is to combine Machin’s formula:
http://lostmathlessons.blogspot.com/2016/03/using-your-computer-to-calculate-pi.html
'''
# Pi Calculator
# Python 2.7.3
# After running, type "pi(n)" where n is the number of decimals for pi. For
# example, if you would like to calculate 100 decimals for pi, type "pi(100)".
# import python libraries
from decimal import Decimal, getcontext
from time import time, strftime
import datetime
# arccot function using power formula arccot = 1/x - 1/(3x^3) + 1/(5x^5) ...
def arccot(x, digits):
# set precision and starting values
getcontext().prec = digits
total = 0
n = 1
# loop while new term is large enough to actually change the total
while Decimal((2 * n - 1) * x ** (2 * n - 1)) < Decimal(10 ** digits):
# find value of new term
term = ((-1)**(n - 1)) * 1 / Decimal((2 * n - 1) * x ** (2 * n - 1))
# add the new term to the total
total += term
# next n
n += 1
# return the sum
return total
# pi function
def pi(decimals):
# start timer
timestart = time()
# find pi using Machin's Formula pi = 4 * (4 * arccot(5) - arccot(239))
# and the power formula for arccot (see arccot function above)
print "pi = "+ str(Decimal(4*(4*arccot(5,decimals+3)-arccot(239,decimals+3))).quantize(Decimal(10)**(-decimals)))
# display elapsed time
timeelapsedint = round(time()-timestart,2)
timeelapsedstr = str(datetime.timedelta(seconds = round(timeelapsedint, 0)))
print "runtime: " + timeelapsedstr + " or " + str(timeelapsedint) + " seconds."
pi(1000)
Używamy modułu wieloprocesorowego Pythona do wykonania długiego zadania w oddzielnym procesie. Ten pakiet obsługuje procesy odradzania przy użyciu API podobnego do modułu wątków. Moduł przetwarzania wieloprocesowego działa inaczej w systemach Windows i Linux. W systemie Linux wywoływane jest wywołanie fork(), natomiast w systemie Windows używany jest moduł pickle. Ma to pewne ważne konsekwencje. Podzielimy przykład kodu na programy Linux i Windows.
Jest jedno ograniczenie naszego programu. Używa obiektu Queue do wymiany wartości między procesami. Ta kolejka ma limit rozmiaru wartości, którą może otrzymać. Rozmiar jest określany przez potok OS. Po przekroczeniu tego limitu program kończy się impasem. Największe Pi obliczone na Windows 7 miało 8156 cyfr. W systemie Linux udało nam się obliczyć ponad 60 000 cyfr Pi.
Osobiście uważam, i widzę z powyższych doświadczeń, że poniższy kod jest najmniej wydajny. Tzn. Powyższe dwa kody znacznie szybciej wyliczą zdecydowanie większa ilość cyfr liczby Pi w znacznie krótszym czasie. Ale program ma okienka ... bez komentarza.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ZetCode Tkinter e-book
This script produces a long-running task of calculating
a large Pi number, while keeping the GUI responsive.
Author: Jan Bodnar
Last modified: January 2016
Website: www.zetcode.com
http://zetcode.com/articles/tkinterlongruntask/
"""
from tkinter import (Tk, BOTH, Text, E, W, S, N, END,
NORMAL, DISABLED, StringVar)
from tkinter.ttk import Frame, Label, Button, Progressbar, Entry
from tkinter import scrolledtext
from multiprocessing import Queue, Process
import queue
from decimal import Decimal, getcontext
DELAY1 = 80
DELAY2 = 20
class Example(Frame):
def __init__(self, parent, q):
Frame.__init__(self, parent)
self.queue = q
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Pi computation")
self.pack(fill=BOTH, expand=True)
self.grid_columnconfigure(4, weight=1)
self.grid_rowconfigure(3, weight=1)
lbl1 = Label(self, text="Digits:")
lbl1.grid(row=0, column=0, sticky=E, padx=10, pady=10)
self.ent1 = Entry(self, width=10)
self.ent1.insert(END, "4000")
self.ent1.grid(row=0, column=1, sticky=W)
lbl2 = Label(self, text="Accuracy:")
lbl2.grid(row=0, column=2, sticky=E, padx=10, pady=10)
self.ent2 = Entry(self, width=10)
self.ent2.insert(END, "100")
self.ent2.grid(row=0, column=3, sticky=W)
self.startBtn = Button(self, text="Start",
command=self.onStart)
self.startBtn.grid(row=1, column=0, padx=10, pady=5, sticky=W)
self.pbar = Progressbar(self, mode='indeterminate')
self.pbar.grid(row=1, column=1, columnspan=3, sticky=W+E)
self.txt = scrolledtext.ScrolledText(self)
self.txt.grid(row=2, column=0, rowspan=4, padx=10, pady=5,
columnspan=5, sticky=E+W+S+N)
def onStart(self):
self.startBtn.config(state=DISABLED)
self.txt.delete("1.0", END)
self.digits = int(self.ent1.get())
self.accuracy = int(self.ent2.get())
self.p1 = Process(target=self.generatePi, args=(self.queue,))
self.p1.start()
self.pbar.start(DELAY2)
self.after(DELAY1, self.onGetValue)
def onGetValue(self):
if (self.p1.is_alive()):
self.after(DELAY1, self.onGetValue)
return
else:
try:
self.txt.insert('end', self.queue.get(0))
self.txt.insert('end', "\n")
self.pbar.stop()
self.startBtn.config(state=NORMAL)
except queue.Empty:
print("queue is empty")
def generatePi(self, queue):
getcontext().prec = self.digits
pi = Decimal(0)
k = 0
n = self.accuracy
while k < n:
pi += (Decimal(1)/(16**k))*((Decimal(4)/(8*k+1)) - \
(Decimal(2)/(8*k+4)) - (Decimal(1)/(8*k+5))- \
(Decimal(1)/(8*k+6)))
k += 1
print (self.p1.is_alive())
queue.put(pi)
print("end")
def main():
q = Queue()
root = Tk()
root.geometry("400x350+300+300")
app = Example(root, q)
root.mainloop()
if __name__ == '__main__':
main()
Bardzo szybki programik. Efekty widać od razu. Warto skierować dane wynikowe do pliku.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# http://rosettacode.org/wiki/Pi
def calcPi():
q, r, t, k, n, l = 1, 0, 1, 1, 3, 3
while True:
if 4*q+r-t < n*t:
yield n
nr = 10*(r-n*t)
n = ((10*(3*q+r))//t)-10*n
q *= 10
r = nr
else:
nr = (2*q+r)*l
nn = (q*(7*k)+2+(r*l))//(t*l)
q *= k
t *= l
l += 2
k += 1
n = nn
r = nr
import sys
pi_digits = calcPi()
i = 0
for d in pi_digits:
sys.stdout.write(str(d))
#i += 1
#if i == 60: print(""); i = 0
Z obliczeniami Pi jest taki problem, że kolejne cyfry zajmują miejsce w pamięci komputerów, w tym dysków twardych. Poniższe pokazuje jak szybko zapełniamy tymi cyframi wszelkie pamięci. Więc nim się weźmiesz za liczenie na swoim komputerze pomyśl, czy to w ogóle jest możliwe:
Z biegiem lat uzyskiwano coraz lepsze przybliżenia wartości π sięgające kilkuset miejsc po przecinku. W 1853 William Rutherford podał liczbę Pi z dokładnością 440 miejsc po przecinku. Rekordzistą w ręcznych obliczeniach liczby Pi jest William Shanks, któremu w 1874 udało się uzyskać 707 miejsc po przecinku. Zajęło mu to 15 lat. Później okazało się, że 180 ostatnich cyfr obliczył błędnie (wynik, który uznano za prawidłowy uwzględnia 527 miejsc po przecinku). W 1946 roku Ferguson podał wartość π do 620. miejsca po przecinku. W końcowych obliczeniach wspomagał się już kalkulatorem. Od 1949, kiedy to przy pomocy komputera ENIAC obliczono 2038 miejsc po przecinku, dokładniejsze aproksymacje liczby π uzyskiwano już tylko przy użyciu komputerów. We wrześniu 1999 roku obliczono π z dokładnością 2,0615·1011 miejsc po przecinku. Dokonał tego Takahasi przy pomocy komputera Hitachi SR8000 - Link.
31 grudnia 2009 r. Fabrice Bellard ogłosił, że udało mu się obliczyć π z dokładnością do 2 700 miliardów cyfr. Obliczenia ze sprawdzeniem zajęły 131 dni, do obliczeń użyto komputera z procesorem Intel Core i7 (2,93 GHz) i 6 GB RAM. Sam zapis binarny liczby zajmuje około 1,12 TB.
W roku 2010 obliczono cyfrę będącą na 2 000 000 000 000 000 miejscu po przecinku w rozwinięciu dziesiętnym liczby pi i wynosi ona zero. Obliczenia trwały 23 dni na 1000 maszynach.
W październiku 2011 Alexander J. Yee i Shigeru Kondo uzyskali dokładność ok. 10 bilionów (1013) miejsc po przecinku. Obliczenia zajęły 371 dni.
W październiku 2014 anonimowa osoba o nicku houkouonchi uzyskała dokładność ok. 13,3 bilionów miejsc po przecinku. Obliczenia zajęły 208 dni, a sprawdzanie 182 godziny.
W listopadzie 2016 Peter Trueb uzyskał dokładność ok. 22,5 bilionów miejsc po przecinku przy pomocy programu y-cruncher. Obliczenia zajęły 105 dni, a sama liczba zajęła ok. 120 TB miejsca.
A teraz porównanie kilku algorytmów na Pi:
31 grudnia 2009 r. Fabrice Bellard ogłosił, że udało mu się obliczyć π z dokładnością do 2 700 miliardów cyfr. Obliczenia ze sprawdzeniem zajęły 131 dni, do obliczeń użyto komputera z procesorem Intel Core i7 (2,93 GHz) i 6 GB RAM. Sam zapis binarny liczby zajmuje około 1,12 TB.
W roku 2010 obliczono cyfrę będącą na 2 000 000 000 000 000 miejscu po przecinku w rozwinięciu dziesiętnym liczby pi i wynosi ona zero. Obliczenia trwały 23 dni na 1000 maszynach.
W październiku 2011 Alexander J. Yee i Shigeru Kondo uzyskali dokładność ok. 10 bilionów (1013) miejsc po przecinku. Obliczenia zajęły 371 dni.
W październiku 2014 anonimowa osoba o nicku houkouonchi uzyskała dokładność ok. 13,3 bilionów miejsc po przecinku. Obliczenia zajęły 208 dni, a sprawdzanie 182 godziny.
W listopadzie 2016 Peter Trueb uzyskał dokładność ok. 22,5 bilionów miejsc po przecinku przy pomocy programu y-cruncher. Obliczenia zajęły 105 dni, a sama liczba zajęła ok. 120 TB miejsca.
from decimal import *
#Sets decimal to 25 digits of precision
#http://blog.recursiveprocess.com/2013/03/14/calculate-pi-with-python/
getcontext().prec = 25
def factorial(n):
if n<1:
return 1
else:
return n * factorial(n-1)
def plouffBig(n): #http://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula
pi = Decimal(0)
k = 0
while k < n:
pi += (Decimal(1)/(16**k))*((Decimal(4)/(8*k+1))-(Decimal(2)/(8*k+4))-(Decimal(1)/(8*k+5))-(Decimal(1)/(8*k+6)))
k += 1
return pi
def bellardBig(n): #http://en.wikipedia.org/wiki/Bellard%27s_formula
pi = Decimal(0)
k = 0
while k < n:
pi += (Decimal(-1)**k/(1024**k))*( Decimal(256)/(10*k+1) + Decimal(1)/(10*k+9) - Decimal(64)/(10*k+3) - Decimal(32)/(4*k+1) - Decimal(4)/(10*k+5) - Decimal(4)/(10*k+7) -Decimal(1)/(4*k+3))
k += 1
pi = pi * 1/(2**6)
return pi
def chudnovskyBig(n): #http://en.wikipedia.org/wiki/Chudnovsky_algorithm
pi = Decimal(0)
k = 0
while k < n:
pi += (Decimal(-1)**k)*(Decimal(factorial(6*k))/((factorial(k)**3)*(factorial(3*k)))* (13591409+545140134*k)/(640320**(3*k)))
k += 1
pi = pi * Decimal(10005).sqrt()/4270934400
pi = pi**(-1)
return pi
print ("\t\t\t Plouff \t\t Bellard \t\t\t Chudnovsky")
for i in range(1,20):
print ("Iteration number ",i, " ", plouffBig(i), " " , bellardBig(i)," ", chudnovskyBig(i))
I jeszcze dwa skrypty Python3 dal obliczania Pi:
""" Python3 program to calculate Pi using python long integers, and the Chudnovsky algorithm See: http://www.craig-wood.com/nick/articles/pi-chudnovsky/ for more info Nick Craig-WoodPoniższy wymaga zainstalowania biblioteki gmpy2 - Link na stronie autora skryptu znajdziemy linki do biblioteki oraz instrukcje. W Linux'ie dla Python'a najprościej zainstalować ją poprzez sudo pip3 install gmpy2. Gdyby pojawiły się problemy z instalacją, zapewne zabraknie bibliotek, to należy je doinstalować. Wcześniej przeczytać wygenerowany opis.""" import math from time import time def sqrt(n, one): """ Return the square root of n as a fixed point number with the one passed in. It uses a second order Newton-Raphson convgence. This doubles the number of significant figures on each iteration. """ # Use floating point arithmetic to make an initial guess floating_point_precision = 10**16 n_float = float((n * floating_point_precision) // one) / floating_point_precision x = (int(floating_point_precision * math.sqrt(n_float)) * one) // floating_point_precision n_one = n * one while 1: x_old = x x = (x + n_one // x) // 2 if x == x_old: break return x def pi_chudnovsky(one=1000000): """ Calculate pi using Chudnovsky's series This calculates it in fixed point, using the value for one passed in """ k = 1 a_k = one a_sum = one b_sum = 0 C = 640320 C3_OVER_24 = C**3 // 24 while 1: a_k *= -(6*k-5)*(2*k-1)*(6*k-1) a_k //= k*k*k*C3_OVER_24 a_sum += a_k b_sum += k * a_k k += 1 if a_k == 0: break total = 13591409*a_sum + 545140134*b_sum pi = (426880*sqrt(10005*one, one)*one) // total return pi if __name__ == "__main__": print(pi_chudnovsky(10**100)) for log10_digits in range(1,7): digits = 10**log10_digits one = 10**digits start =time() pi = pi_chudnovsky(one) #print(pi) print("chudnovsky: digits",digits,"time",time()-start)
Skrypt ten ma już poprawiny zawarty w nim błąd. Więc nieco się różni od oryginału. Bibliotek GMPY2 pozwala na realizację obliczeń na dużych liczbach z odpowiednią precyzją. System i Python mają swoje ograniczenia. Wielkie liczby ... trzeba je obejść.
""" Python3 program to calculate Pi using python long integers, binary splitting and the Chudnovsky algorithm See: http://www.craig-wood.com/nick/articles/pi-chudnovsky/ for more info Nick Craig-Woodhttps://www.craig-wood.com/nick/articles/pi-chudnovsky/ """ import math from gmpy2 import mpz, isqrt from time import time def pi_chudnovsky_bs(digits): """ Compute int(pi * 10**digits) This is done using Chudnovsky's series with binary splitting """ C = 640320 C3_OVER_24 = C**3 // 24 def bs(a, b): """ Computes the terms for binary splitting the Chudnovsky infinite series a(a) = +/- (13591409 + 545140134*a) p(a) = (6*a-5)*(2*a-1)*(6*a-1) b(a) = 1 q(a) = a*a*a*C3_OVER_24 returns P(a,b), Q(a,b) and T(a,b) """ if b - a == 1: # Directly compute P(a,a+1), Q(a,a+1) and T(a,a+1) if a == 0: Pab = Qab = mpz(1) else: Pab = mpz((6*a-5)*(2*a-1)*(6*a-1)) Qab = mpz(a*a*a*C3_OVER_24) Tab = Pab * (13591409 + 545140134*a) # a(a) * p(a) if a & 1: Tab = -Tab else: # Recursively compute P(a,b), Q(a,b) and T(a,b) # m is the midpoint of a and b m = (a + b) // 2 # Recursively calculate P(a,m), Q(a,m) and T(a,m) Pam, Qam, Tam = bs(a, m) # Recursively calculate P(m,b), Q(m,b) and T(m,b) Pmb, Qmb, Tmb = bs(m, b) # Now combine Pab = Pam * Pmb Qab = Qam * Qmb Tab = Qmb * Tam + Pam * Tmb return Pab, Qab, Tab # how many terms to compute DIGITS_PER_TERM = math.log10(C3_OVER_24/6/2/6) N = int(digits/DIGITS_PER_TERM + 1) # Calclate P(0,N) and Q(0,N) P, Q, T = bs(0, N) one_squared = mpz(10)**(2*digits) sqrtC = isqrt(10005*one_squared) return (Q*426880*sqrtC) // T # The last 5 digits or pi for various numbers of digits check_digits = { 100 : 70679, 1000 : 1989, 10000 : 75678, 100000 : 24646, 1000000 : 58151, 10000000 : 55897, } if __name__ == "__main__": digits = 100 pi = pi_chudnovsky_bs(digits) print(pi) #raise SystemExit for log10_digits in range(1,9): digits = 10**log10_digits start =time() pi = pi_chudnovsky_bs(digits) print("chudnovsky_gmpy_mpz_bs: digits",digits,"time",time()-start) if digits in check_digits: last_five_digits = pi % 100000 if check_digits[digits] == last_five_digits: print("Last 5 digits %05d OK" % last_five_digits) else: print("Last 5 digits %05d wrong should be %05d" % (last_five_digits, check_digits[digits]))
Dodaj komentarz
Zaloguj się, aby móc dodać komentarz.
Oceny
Tylko zarejestrowani użytkownicy mogą oceniać zawartość strony
Zaloguj się , żeby móc zagłosować.
Zaloguj się , żeby móc zagłosować.
Brak ocen. Może czas dodać swoją?



















































