2016-01-17 59 views
7

Sono un nuovo membro qui e ho intenzione di andare dritto in questo mentre ho passato tutta la domenica a cercare di capirlo.Non riesco a calcolare con precisione pi su Python

Sono nuovo di Python, avendo precedentemente imparato la codifica su C++ a livello di base-intermedio (era un modulo universitario di 10 settimane).

Sto provando un paio di tecniche iterative per calcolare Pi, ma entrambe sono leggermente imprecise e non sono sicuro del perché.

Il primo metodo che ho imparato all'università - sono sicuro che alcuni di voi l'hanno già visto prima.

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 

È essenzialmente un generatore per casuale (x, y) coordinate su un aereo da -1 a +1 su entrambi gli assi. Quindi se x^2 + y^2 < = 1, sappiamo che il punto poggia all'interno di un cerchio di raggio 1 all'interno del riquadro formato dagli assi di coordinate.

A seconda della posizione del punto, un contatore aumenta per incircle o outcircle.

Il valore per pi è quindi il rapporto tra i valori all'interno e all'esterno del cerchio. Le coordinate sono generate casualmente quindi dovrebbe essere una diffusione uniforme.

Tuttavia, anche a valori di iterazione molto elevati, il mio risultato per Pi è sempre intorno al segno di 3,65.

Il secondo metodo è un'altra iterazione che calcola la circonferenza di un poligono con un numero crescente di lati fino a quando il poligono è quasi un cerchio, quindi, Pi = Circonferenza/diametro. (In qualche modo ho imbrogliato perché la codifica ha un termine math.cos (Pi) quindi sembra che sto usando Pi per trovare Pi, ma questo è solo perché non puoi usare facilmente i gradi per rappresentare gli angoli su Python). Ma anche per alte iterazioni il risultato finale sembra finire intorno a 3,20, che di nuovo è sbagliato. Il codice è qui:

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 

Mi ricordo, quando facendo il mio C++ naturalmente, viene detto che il problema è comune e non è a causa della matematica, ma a causa di qualcosa all'interno della codifica, tuttavia posso Ricordo esattamente. Potrebbe avere a che fare con la generazione di numeri casuali, o con i limiti dell'utilizzo di numeri in virgola mobile, o ... qualcosa in realtà. Potrebbe anche essere solo la mia matematica ...

Qualcuno può pensare qual è il problema?

TL; DR: Cercando di calcolare Pi, posso avvicinarmi ad esso ma mai in modo molto accurato, non importa quante iterazioni faccio.

(Oh e un altro punto: nel secondo codice c'è una riga che dice S = 2,0 ** k. Se imposto 'n' su qualcosa di superiore a 2000, il valore di S diventa troppo grande da gestire e il codice si blocca Come posso risolvere questo problema?)

Grazie!

+0

Questo è un problema di matematica. Il metodo di Monte-Carlo fornisce un'approssimazione di pi, non pi stesso. [Questo] (http://rosettacode.org/wiki/Pi#Python) dovrebbe essere più preciso. – Rolbrok

+0

Ho anche notato che pitone a volte è un po 'fuori dai suoi calcoli. Ad esempio, quando si applica 'tan (45)' gradi restituisce 0.99999 ... invece di 1. –

+0

@AshwinGupta Questa non è una lacuna di solo Python, ma qualsiasi linguaggio che implementa l'aritmetica in virgola mobile. Inoltre, è tan (45) uguale a 1. – Reti43

risposta

7

L'algoritmo per la prima versione dovrebbe essere più simile a questo:

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) 

Stampe:

3.14699146991 

Questo è più vicino. Aumentare n per avvicinarsi ancora di pi.

Il algorithm prende in considerazione solo un quarto del cerchio unitario, vale a dire con un raggio di 1.

La formula per l'area di un quarto di cerchio è:

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

Che per l'area del quadrato contenente questo cerchio:

area_s = r **2 

dove r è il raggio del cerchio.

Ora il rapporto è:

area_c/area_s 

sostitutivi le equazioni di cui sopra, ri-arange e si ottiene:

pi = 4 * (area_c/area_s) 

Andando Monte Carlo, basta sostituire entrambe le aree con un numero molto elevato che rappresenta loro. In genere, qui viene utilizzata l'analogia delle freccette lanciate casualmente.

+0

Dannazione, stavo solo postando :). Oh beh, non proprio un tipo pitone comunque. –

+0

È (quattro volte) il rapporto tra i punti nel mezzo di tutti i punti, solo i punti all'esterno ... Dovresti menzionarlo. –

+0

Ahhh giusto, grazie! Lo capisco adesso. Ammetto che stavo passando dalla memoria alla memoria (più di un anno fa) e, piuttosto stupidamente, senza fermarmi a pensare alla matematica di base che stava dietro, mi sembrava di pensare che fosse semplicemente (incircle/outcircle) ma ora, avendo rovistato attraverso alcuni vecchi file e trovato il codice C++ originale, effettivamente usa il metodo spiegato qui. Grazie ancora. –

2

Per il primo, il calcolo dovrebbe essere

pi = incircle/1000000*4 # 3.145376.. 

Questo è il numero di punti che è atterrato all'interno del cerchio sul numero di punti totali (circa 0,785,671 mila sulla mia corsa).

Con un raggio di 1 (random.uniform(-1,1)), l'area totale è 4, quindi se si multipli di 4 in base al rapporto dei punti che sono atterrati all'interno del cerchio, si ottiene la risposta corretta.