Choinka programisty Ruby
Czy programiści Ruby 💎 programują swoje choinki 🎄 święteczne?
Jak Archimedes przybliżył liczbę pi? Od wieków posiadano wiedzę, że stosunek obwodu (ang. circumference) koła do jego średnicy (ang. diameter) C/d jest stały. Ta stała wartość to właśnie π. Jeżeli rozważyć koło o średnicy 1 wtedy jego obwód będzie równy pi. To był punkt wyjścia. Następnie Archimedes zaczął wpisywać w koło oraz opisywać na nim wielokąty foremne. Obwód wielokąta wpisanego był mniejszy od obwodu koła (tym samym zawężał dolną granicę pi). Natomiast obwód wielokąta opisanego był większy (co wyznaczało górną granicę pi). W ten sposób wskazał przedział w jakim należy szukać pi. Przeprowadził pierwszą aproksymację tej liczby. Dokonując wyliczeń dla 96-kąta foremnego, udało mu się ustalić liczbę pi do dwóch miejsc po przecinku.
Dość długo ta metoda służyła do kolejnych wyliczeń π. Z czasem pojawiły się inne sposoby na aproksymację liczby pi. Zalicza się do nich aproksymację za pomocą ciągów nieskończonych. Poniżej kilka przykładów.
Jako pierwszą aproksymację w Europie, przy użyciu ciągów nieskończonych, podaje się wzór Viète. Za jego pomocą udało się obliczyć pi do dziewięciu miejsc po przecinku. Można znaleźć jego dwa zapisy:
lub
Nie bylibyśmy sobą gdybyśmy nie pokusili się o napisanie krótkiej metody w Ruby. 💎
def approximation_pi_with_viete_formula(n)
factor = 2.0
return factor if n == 0
denominator = Math.sqrt(2)
product = factor
product *= factor / denominator
return product if n == 1
n.times do
new_denominator = Math.sqrt(2 + denominator)
product *= factor / new_denominator
denominator = new_denominator
end
product
end
Jako drugą w Europie podaje się aproksymację John’a Wallis’a. Jest ona łatwa w zastosowaniu ponieważ opiera się na granicy ciągu liczb wymiernych. Wzór przedstawia się następująco:
Dla naszych programistycznych potrzeb można przenieść 2 na drugą stronę równania.
def approximation_pi_with_wallis_formula(n)
product = 1.0
n.times do |k|
counter = 2.0 * (k + 1)
first_factor = counter / (counter - 1)
second_factor = counter / (counter + 1)
product *= first_factor * second_factor
end
2 * product
end
Znana również pod dwoma innymi nazwami: Gregory - Leibniz lub Gregory - Leibniz - Madhava. Pozwala ona na wyznaczenie pi z dużą precyzją. Jest to jednak tak zwana “wolno zbieżna” metoda. Za jej pomocą należy wykonać zdecydowanie więcej obliczeń aby uzyskać wynik. Nakład pracy w obliczenia jest niesamowicie duży w porównaniu z innymi sposobami. Wzór na aproksymację Leibniz’a to:
Jak może wyglądać przykładowa metoda dla tej aproksymacji?
def approximation_pi_with_leibniz_formula(n)
4 * n.times.sum do |k|
1.0 / (4 * k + 1) - 1.0 / (4 * k + 3)
end
end
Tu również, dla czytelności uzyskanego wyniku, 4 można przenieść na drugą stronę równania.
Swoje rozwiązanie przybliżenia wartości π zaprezentował indyjski astronom Nilakantha Somayaji. Aproksymacja Nilakantha okazała się szybciej zbieżna, a wzór ma postać:
Jego implemetacja w Ruby może wyglądać następująco:
def approximation_pi_with_nilakantha_formula(n)
one = -1.0
3.0 + 4 * n.times.sum do |k|
one = -one
one / ((2 * k + 2) * (2 * k + 3) * (2 * k + 4))
end
end
Powyższe przykłady aproksymacji liczby pi są już wiekowe. Można by pomyśleć, że przez tak długi czas nic nowego się nie pojawiło. Matematyka jednak nadal się rozwija. Technologia również pozwala nam na osiąganie lepszych wyników m.in obliczeniowych. Fakt ten wykorzystują nowe pokolenia miłośników π i jej aproksymacji.
Cóż oznacza ten tajemniczy skrót? Pochodzi on od nazwisk osób, które opublikowały swoją metodę pod koniec XX wieku: David H. Bailey, Peter Borwein i Simon Plouffe. Przedstawili oni wzór
pozwalający na obliczanie w systemie szesnastkowym n-tej liczby pi bez konieczności wyliczania poprzedzających cyfr. Pozwala to na zrównoleglenie prac obliczeniowych np. na superkomputerach. Spróbujmy obliczyć π na naszym “superkomputerze”.
def approximation_pi_with_bbp_formula(n)
denominator = 1.0
n.times.sum do |k|
part = 8 * k
factor = 4.0 / (part + 1) - 2.0 / (part + 4) - 1.0 / (part + 5) - 1.0 / (part + 6)
result = factor / denominator
denominator *= 16
result
end
end
Na koniec tego artykułu wspomnimy jeszcze o jednej metodzie. Nie będzie się ona opierać na ciągach. Tym razem do aproksymacji posłuży nam ułamek łańcuchowy. Istnieje wiele ułamków łańcuchowych za pomocą, których przybliża się wartość pi. Poniżej podamy rozwiązanie przedstawione przez Thomas’a J. Pickett’a i Ann Coleman.
oraz jego wersję w Ruby.
class PiFromContinuedFraction
def initialize(depth)
@depth = depth
end
def calculate
2 * (1 + 1 / continued_fraction(depth, 1))
end
private
attr :depth
def continued_fraction(depth, number)
result = 1.0 / number
result += 1 / continued_fraction(depth - 1, number + 1) if depth > 0
result
end
end
Możliwości aproksymacji jest wiele. Gdybyśmy próbowali poruszyć wszystkie z nich musiałaby powstać wielotomowa książka. 📚
Próby przybliżenia liczby pi to dobry sposób na odświeżenie wiedzy z matematyki lub jej poszerzenie. To okazja na ciekawe wykorzystanie umiejętności programistycznych i komputera. Jeśli ten ostatni odmówi współpracy - pamiętaj, zawsze jest Cieszyn i nasz serwis. Przy okazji można zwiedzić ładne okolice. 🚶
Zostaw komentarz