2016-01-17 35 views
7

Jestem nowym członkiem tutaj i zamierzam wjechać prosto w to, ponieważ spędziłem całą moją niedzielę próbując zrozumieć.Nie można dokładnie obliczyć pi na Pythonie

Jestem nowy w Pythonie, ponieważ wcześniej nauczyłem się kodowania w C++ na poziomie podstawowym i średnio-zaawansowanym (był to 10-tygodniowy moduł uniwersytecki).

Próbuję kilka iteracyjnych technik do obliczenia Pi, ale oba są nieco niedokładne i nie jestem pewien dlaczego.

Pierwsza metoda, której uczyłem się na uniwersytecie - jestem pewien, że niektórzy z was już to widzieli.

x=0.0 
y=0.0 
incircle = 0.0 
outcircle = 0.0 
pi = 0.0 
i = 0 
while (i<100000): 
    x = random.uniform(-1,1) 
    y = random.uniform(-1,1) 
    if (x*x+y*y<=1): 
     incircle=incircle+1 
    else: 
     outcircle=outcircle+1 
    i=i+1 
pi = (incircle/outcircle) 
print pi 

To zasadniczo generator losowy (x, y) współrzędnych na płaszczyźnie od -1 do +1 na obu osiach. Następnie, jeśli x^2 + y^2 < = 1, wiemy, że punkt spoczywa wewnątrz okręgu o promieniu 1 w polu utworzonym przez współrzędne osi.

W zależności od położenia punktu, licznik zwiększa się dla incircle lub outcircle.

Wartość pi jest to stosunek wartości wewnątrz i na zewnątrz koła. Współrzędne są generowane losowo, więc powinno być równomiernie rozłożone.

Jednak nawet przy bardzo wysokich wartościach iteracji, mój wynik dla Pi jest zawsze wokół znaku 3.65.

Druga metoda to kolejna iteracja, która oblicza obwód wielokąta ze zwiększającą się liczbą boków, aż wielokąt jest prawie okręgiem, a następnie Pi = Obwód/średnica. (W pewien sposób oszukałem, ponieważ kodowanie ma termin math.cos (Pi), więc wygląda na to, że używam Pi do znalezienia Pi, ale dzieje się tak tylko dlatego, że nie możesz łatwo używać stopni do reprezentowania kątów w Pythonie). Ale nawet w przypadku wysokich iteracji końcowy rezultat wydaje się zakończyć około 3,20, co znowu jest błędne. Kod jest tutaj:

S = 0.0 
C = 0.0 
L = 1.0 

n = 2.0 
k = 3.0 
while (n<2000): 
    S = 2.0**k 
    L = L/(2.0*math.cos((math.pi)/(4.0*n))) 
    C = S*L 
    n=n+2.0 
    k=k+1.0 

pi = C/math.sqrt(2.0) 
print pi 

Pamiętam, kiedy robi mój C++ Oczywiście, będąc powiedział, że problem jest powszechny, a nie ze względu na matematyce, ale z powodu czegoś w kodowaniu, jednak mogę nie pamiętam dokładnie. Może to dotyczyć generowania losowych liczb lub ograniczeń używania liczb zmiennoprzecinkowych lub ... cokolwiek naprawdę. To może być nawet moja matematyka ...

Czy ktoś może pomyśleć, co to jest problem?

TL; DR: Próbując obliczyć Pi, mogę zbliżyć się do niego, ale nigdy niezbyt dokładnie, bez względu na to, ile wykonuję iteracji.

(Oh i inny punkt - w drugim kodzie znajduje się wiersz z napisem S = 2,0 ** k. Jeśli ustawię "n" na wartość wyższą niż 2000, wartość S staje się zbyt duża, aby obsłużyć, a kod ulega awarii Jak mogę to naprawić?)

Dzięki!

+0

To jest problem matematyczny. Metoda Monte-Carlo podaje przybliżenie pi, a nie pi. [This] (http://rosettacode.org/wiki/Pi#Python) powinno być dokładniejsze. – Rolbrok

+0

Zauważyłem również, że Python jest czasami trochę poza jego obliczeń. Na przykład przy zastosowaniu 'tan (45)' degrees zwraca 0.99999 ... zamiast 1. –

+0

@AshwinGupta Nie jest to wada tylko Pythona, ale dowolnego języka implementującego arytmetykę zmiennoprzecinkową. Ponadto, jest tan (45), który jest równy 1. – Reti43

Odpowiedz

7

Algorytm Twoja pierwsza wersja powinna wyglądać mniej więcej tak:

from __future__ import division, print_function 

import sys 
if sys.version_info.major < 3: 
    range = xrange 

import random 


incircle = 0 
n = 100000 
for n in range(n): 
    x = random.random() 
    y = random.random() 
    if (x*x + y*y <= 1): 
     incircle += 1 
pi = (incircle/n) * 4 
print(pi) 

Wydruki:

3.14699146991 

Jest bliżej. Zwiększ n, aby jeszcze bardziej zbliżyć się do pi.

Urządzenie algorithm uwzględnia tylko jedną czwartą koła jednostki, tj. O promieniu 1.

Wzór na powierzchni jednej czwartej okręgu jest:

area_c = (pi * r **2)/4 

że na powierzchni kwadratu zawierającego ten okrąg:

area_s = r **2 

gdzie r jest promieniem okręgu.

Teraz stosunek wynosi:

area_c/area_s 

zastępcze równania powyżej, ponownie arange i masz:

pi = 4 * (area_c/area_s) 

Idąc Monte Carlo, po prostu zastąpić oba obszary o bardzo dużej liczbie reprezentującej im. Zazwyczaj używa się tu analogii rzucanych losowo.

+0

Cholera, właśnie to opublikowałem :). No cóż, tak naprawdę nie jest to gość z Pythona. –

+0

Jest to (cztery razy) stosunek punktów w środku do wszystkich punktów, tylko punkty na zewnątrz ... Powinieneś o tym wspomnieć. –

+0

Ahhh w porządku, dzięki! Teraz rozumiem. Przyznaję, że właśnie przechodziłem kodowanie z pamięci (ponad rok temu) i, raczej głupio, nie przestając myśleć o podstawowej matematyce, wydawało mi się, że to po prostu (incircle/outcircle), ale teraz, po grzebaniu poprzez stare pliki i znalazł oryginalny kod C++, rzeczywiście używa metody wyjaśnionej tutaj. Dzięki jeszcze raz. –

2

Dla pierwszego, Twój kalkulacja powinna być

pi = incircle/1000000*4 # 3.145376.. 

Jest to liczba punktów, które wylądowały wewnątrz okręgu na łączną liczbę punktów (około 0.785671 w moim biegu).

Przy promieniu 1 (random.uniform(-1,1)), całkowita powierzchnia wynosi 4, więc jeśli masz kilka 4 w stosunku do punktów, które wylądowały wewnątrz okręgu, otrzymasz poprawną odpowiedź.