2016-11-27 1 views
4

У меня есть задание, где мне нужно приближенно вычислять Pi. Вот моя стратегия: я использую единичный круг, биссектрису угла изоцелевого треугольника и определение греха. Я нарисовал схему:Python: оцените Pi с функциями триггера как можно эффективнее

enter image description here

Например, если я хочу использовать шестигранник (6 баллов/6 сторон), я просто нужно вычислить a :(0.5*sin(2*pi/2*x) и умножить его на(). Наконец, начиная с Pi = Circumference/Diameter, тогда мое приближение Pi = полигональный периметр (с Diameter = 1).

По существу:

from math import sin, pi 
def computePi(x): #x: number of points desired 
    p = x*sin(pi/x) 
    print(p) 

computePi(10000) 
3.141592601912665 

Он работает, и я думаю, что это столь же эффективным, как он получает, нет? Спасибо за ваше время!

EDIT: чтобы избежать цикличности, я переделал его, используя алгоритм Архимеда, используя только Пифагора theroem:

enter image description here

Код:

from math import sqrt 

def approxPi(x):     #x: number of times you want to recursively apply Archmidedes' algorithm 
    s = 1       #Unit circle 
    a = None; b = None; 
    for i in range(x): 
     a = sqrt(1 - (s/2)**2) 
     b = 1 - a 
     print('The approximate value of Pi using a {:5g}-sided polygon is {:1.8f}'.format(6*2**(i),(s*6*2**(i))/2)) 
     s = sqrt(b**2 + (s/2)**2) 
+6

так, вы вычислить 'pi' используя значение' pi'? hmm – Uriel

+1

Если вы импортируете pi, почему бы просто не использовать его? – JonahR

+2

На самом деле, это хороший вопрос о домашнем задании (хотя, возможно, вне темы на Stack Overflow, так как это рабочий код). Циркулярность может быть скрыта с помощью 'math.sin (math.radians (y))' где 'y' - соответствующий угол в градусах. Поскольку это исторически точный способ аппроксимации 'pi', можно, например, разделите 360 на 2 степени, чтобы необходимые синусы могли быть вычислены по первому принципу с использованием формулы полуугольника таким образом, чтобы не требовалось предварительного знания «pi». –

ответ

4

Еще лучше

print(4 * math.atan(1)) 

Это не использует pi в очевидном виде при вычислении (tho ugh как @ Jean-FrançoisFabre комментирует, pi, вероятно, используется в определении функции), и в дополнение к триггерной функции он имеет только одно простое умножение. Конечно, есть также

print(2 * math.acos(0)) 

и

print(2 * math.asin(1)) 
+2

Вероятно, он использует pi, но по крайней мере он использует ту, которая определена внутри тригонометрических функций. –

+0

ИЛИ просто используйте 'print (pi)'. Никаких вычислений не требуется –

+0

@MoinuddinQuadri: Но это не использует «функцию триггера», как указано в заголовке вопроса. –

2

Весело хотя и не очень эффективное решение заключается в использовании решение Эйлера о Basel Problem:

from math import sqrt 

def psum(n): 
    return sum(1/k**2 for k in range(1,n+1)) 

def approxPi(n): 
    s = psum(n) 
    return sqrt(6*s) 

Например,

>>> approxPi(100000) 
3.141583104326456 

Как я уже говорил , не очень эффективно. С другой стороны, нет четкой крутизны. Известно, что многие другие серии сходятся к pi или сходятся к значению, из которого можно легко вычислить pi, и многие из этих других серий сходятся гораздо быстрее.

На редактирования: Предложение @Simon «ы использования Gauss-Legendre algorithm вместе с модулем decimal, приводит к следующему коду (который возвращает результат в виде строки):

import decimal 
from decimal import Decimal as d 

def approxPi(n): 
    eps = 1/d(10**n) 
    decimal.getcontext().prec = 3*n #probably overkill, but need room for products 
    a = d(1) 
    b = 1/d(2).sqrt() 
    t = 1/d(4) 
    p = d(1) 
    dif = a-b 
    if dif < 0: dif = -dif 
    i = 1 
    while dif >= eps: 
     a1 = (a+b)/2 
     b1 = a*b 
     b1 = b1.sqrt() 
     t1 = t - p*(a - a1)**2 
     p1 = 2*p 
     a,b,t,p = a1,b1,t1,p1 
     dif = a1-b1 
     if dif < 0: dif = -dif 
    pi = (a + b)**2/(4*t) 
    return str(pi)[:n+2] 

Например,

>>> approxPi(1000) 
'3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989' 

С соглашением с this.

Вышеуказанное заняло менее секунды. Это потребовало нескольких секунд для 10 000.Было бы интересно посмотреть, сколько времени потребуется, чтобы получить с этого 1 000 000 цифр в Python.

+0

Фактически, он должен сходиться к 10000 цифрам в ~ 13 итерациях. «Алгоритм имеет сходящийся характер второго порядка, что по сути означает, что число правильных цифр удваивается с каждым шагом алгоритма». – Simon

+0

1000000 цифр должно быть 20 итераций. – Simon

+0

@Simon Да - но отдельные итерации становятся медленными, когда вы имеете дело с высокой точностью. Взятие квадратного корня из объекта с десятичной точностью в 2 000 000 + (всего одна часть итерации), вероятно, занимает много времени. Я не знаю достаточно о классе «decimal», чтобы оценить, как долго, но если переход от 1000 до 10000 был на порядок больше во времени, 1,000,000 может быть растянутым, по крайней мере, на моем 3-летнем ноутбуке. Я запустил его и посмотрю, что произойдет. –

Смежные вопросы