Doi algoritmi pentru aproximarea numărului
Nimeni: Nimic.
InfoGenius: Astăzi, pe 14 martie, se sărbătorește ziua numărului
Pi este un număr care nu are nevoie de nicio introducere. El este definit drept raportul dintre circumferința și diametrul unui cerc, motiv pentru care această constantă apare adesea în formule și ecuații matematice, dar și fizice.
De fapt, în fizică, apare de cele mai multe ori înmulțit cu Din acest motiv, mulți fizicieni doresc să renunțăm la în favoarea unei constante egală cu Sau, altfel spus, egală cu raportul dintre circumferința unui cerc și raza sa. Din fericire, nimeni nu i-a băgat încă în seamă
Cum matematicienii s-au gândit ca, pe data de 14 a 3-a a fiecărui an, să celebrăm ziua numărului pi. Întâmplător sau nu, această zi are o semnificație deosebită pentru comunitatea științifică:
- 14 martie 1879: S-a născut Albert Einstein.
- 14 martie 2018: A murit Stephen Hawking.
- 14 martie 1994: S-a lansat prima versiune oficială de Linux!
Despre aproximarea numărului pi
După cum bine știți, este un număr irațional, adică are o infinitate de zecimale și nu există niciun tipar după care acestea să se repete. Așadar, nu putem decât să aproximăm valoarea acestei constante. În practică, nu o să avem niciodată nevoie de mai mult de 152 de zecimale ale lui Iată de ce:
Să presupunem că știm diametrul unei sfere și dorim să-i calculăm circumferința. Dacă diametrul acestei sfere ar fi egal cu 93 de miliarde de ani-lumină (diametrul universului observabil), o aproximare a lui la 152 de zecimale ar fi suficientă pentru a obține o eroare cel mult egală cu lungimea Planck – cea mai mică unitate de măsură pentru lungime care are vreo semnificație…
Cu toate acestea, informaticienilor le place să inventeze algoritmi pentru aproximarea lui pi la câteva milioane, miliarde sau chiar trilioane de zecimale. Spre exemplu, ultimul record a fost atins în ianuarie 2020: După ce a muncit din greu 300 și ceva de zile, un super-calculator a reușit să determine primele 50 de trilioane de zecimale ale lui pi! Doborând recordul de doar 31.4 trilioane, stabilit de Google cu un an înainte.
În caz că aceste rezultate vi se par inutile, în mare parte aveți dreptate. Doar că, vânătoarea asta după zecimalele lui este justificată din două motive. În primul rând, este o metodă foarte bună de a pune la încercare puterea computațională a celor mai noi super-calculatoare. În al doilea rând, simpla căutare de algoritmi care să-l aproximeze pe poate fi o problemă de informatică foarte plăcută.
Prin urmare, în acest articol vă voi prezenta doi algoritmi interesanți pentru aproximarea numărului pi. Ce îmi place la ei este că se bazează pe teoria probabilităților și pe geometrie, făcându-i foarte ușor de vizualizat. În plus, demonstrația celui de-al doilea ne arată că, uneori, integralele duble chiar sunt utile.
Metoda seriilor
Înainte să trecem la algoritmii ăia șmecheri, cred că ar trebui să prezint metoda folosită cel mai des în practică. Ei bine, aceasta se bazează pe calculul de serii. Adică pe însumarea termenilor din diverse șiruri infinite, a căror sumă converge la o expresie simplă care-l conține pe Un exemplu celebru de astfel de serie este suma inverselor pătratelor perfecte nenule, numită și The Basel Problem:
Euler a demonstrat în 1741 că această sumă este egală cu Deci, cu cât calculăm mai mulți termeni din acest șir, cu atât vom obține o aproximare mai bună a lui de unde îl putem scoate pe foarte ușor, înmulțind rezultatul cu și extrăgându-i rădăcina pătrată.
Există pagini de Wikipedia pline de astfel de serii, relativ simple, prin care îl putem aproxima pe Dar apoi apar serii ca asta, care duc lucrurile la un cu totul alt nivel:
Este suficient să calculezi termeni din seria asta pentru a obține în mod corect primele zecimale ale lui Nici nu se compară cu seria precedentă, unde după primii de termeni vei obține abia zecimale. Serii de genul ăsta sunt folosite pentru a doborî recorduri ca cel menționat mai sus.
Metoda Monte Carlo
În informatică, un algoritm randomizat se numește Monte Carlo dacă de obicei produce un rezultat foarte apropiat de cel corect, sau Las Vegas dacă returnează mereu răspunsul exact. În continuare, vă voi prezenta un algoritm Monte Carlo foarte simplu, ce poate fi folosit pentru a calcula primele două-trei zecimale ale lui
Fie un pătrat oarecare de latură și fie cercul înscris în pătratul respectiv. Algoritmul se bazează pe ideea că, dacă alegem un punct random din interiorul lui probabilitatea ca acesta să se afle și în interiorul lui este egală cu
De ce? Păi, mai întâi trebuie să calculăm ariile celor două figuri. Aria cercului este iar aria pătratului este Așadar, raportul dintre cele două arii este Și, cred că e destul de intuitiv faptul că acest raport de arii este chiar probabilitatea căutată de noi. (E clar că dacă aria cercului este din aria pătratului, atunci doar puncte din interiorul lui se vor afla și în
Algoritm
Ca să rezum, algoritmul constă în a genera cât mai multe puncte random în interiorul unui pătrat și a determina câte dintre acestea se află la o distanță cel mult egală cu de centrul pătratului. Apoi, împărțim acest număr la numărul total de puncte, înmulțim rezultatul cu și putem spune că l-am aproximat pe
Iată și o vizualizare a acestui algoritm! (Dați click pentru a o lua de la capăt.)
Mai jos aveți și codul sursă pentru această animație, scris în JavaScript și P5.JS. Dacă vreți să vă jucați cu el, dar nu sunteți familiarizați cu cele două, vă recomand să citiți acest articol.
const BLACK = [17, 17, 17];const WHITE = [250, 235, 215];const RED = [255, 69, 0];const RADIUS = 150;
function setup() { createCanvas(300, 350); background(BLACK); noStroke(); textSize(15); textFont('Consolas'); textAlign(CENTER, CENTER);}
let inside = 0;let total = 0;
function draw() { total++; const x = random(0, 2 * RADIUS); const y = random(0, 2 * RADIUS);
fill(WHITE); const sqrDist = (RADIUS - x) * (RADIUS - x) + (RADIUS - y) * (RADIUS - y); if (sqrDist <= RADIUS * RADIUS) { fill(RED); inside++; } circle(x, y, 3);
fill(BLACK); rect(0, 300, 300, 50); fill(WHITE); text('π aproximat: ', width / 2, 315); text(' π real: ', width / 2, 335); fill(RED); text(' ' + (4 * inside / total).toFixed(10), width / 2, 315); text(' ' + PI.toFixed(10), width / 2, 335);}
function mousePressed() { inside = 0; total = 0; fill(BLACK); rect(0, 0, 300, 300);}
Metoda Buffon's Needle
A treia metodă se numește Buffon's Needle, și este oarecum similară cu cea precedentă, în sensul că și ea se bazează pe geometrie și probabilități. Algoritmul presupune să împărțim o foaie de hârtie în mai multe benzi verticale, fiecare de lățime iar apoi să aruncăm pe această foaie chibrituri de lungime unde
Unele chibrituri vor intersecta liniile care separă benzile verticale, pe când altele nu. Raportul dintre numărul chibriturilor care intersectează aceste linii și numărul total de chibrituri aruncate va fi aproximativ Iar dacă alegem ca lățimea unei benzi să fie de două ori mai mare decât lungimea chibritului, adică vom obține direct
Am încercat și eu experimentul, cu două serii de câte de chibrituri, însă n-am obținut cine știe ce rezultat… Doar Dezamăgit că matematica nu vrea să funcționeze în lumea reală, m-am dus la calculator să implementez o simulare a acestui algoritm. A mers ceva mai bine, însă n-am reușit să obțin decât iar asta după câteva minute bune de rulare. Din acest motiv, am fost foarte surprins să citesc că, în 1901, matematicianul Mario Lazzarini a reușit să calculeze corect primele șase zecimale ale lui folosind această metodă. Dar asta, desigur, abia după ce a aruncat chibrituri…
Iată și codul, în caz că vreți să aruncați o privire peste el:
const BLACK = [17, 17, 17];const WHITE = [250, 235, 215];const RED = [255, 69, 0];const LENGTH = 300 / 4;
let good = 0;let total = 0;
function resetBackground() { background(BLACK); strokeWeight(2); stroke(WHITE); for (let i = 0; i < 5; i++) { line(i * LENGTH, 0, i * LENGTH, 300); } noStroke(); strokeWeight(1);}
function setup() { createCanvas(300, 350); frameRate(20); resetBackground(); textSize(15); textFont('Source Code Pro'); textAlign(CENTER, CENTER);}
function draw() { total++; const x = random(0, 300); const y = random(0, 300); const theta = random(0, 2 * PI);
const x1 = x - LENGTH / 4 * cos(theta); const y1 = y - LENGTH / 4 * sin(theta); const x2 = x + LENGTH / 4 * cos(theta); const y2 = y + LENGTH / 4 * sin(theta); for (let i = 0; i < 5; i++) { good += min(x1, x2) < i * LENGTH && i * LENGTH < max(x1, x2); } stroke(RED); line(x1, y1, x2, y2); noStroke();
fill(BLACK); rect(0, 300, 300, 50); fill(WHITE); text('π aproximat: ', width / 2, 315); text(' π real: ', width / 2, 335); fill(RED); text(' ' + (total / good).toFixed(10), width / 2, 315); text(' ' + PI.toFixed(10), width / 2, 335);}
function mousePressed() { good = 0; total = 0; resetBackground();}
Demonstrație
Cred că motivul pentru care această metodă funcționează este mai interesant decât algoritmul în sine. Dacă la metoda Monte Carlo era oarecum clar că avem de a face cu numărul pi – vorba lui 3Blue1Brown, unde dai de un cerc, dai și de pi –, aici e mai complicat. Așadar, în cele ce urmează, voi demonstra de ce algoritmul este corect.
Practic, noi vrem să calculăm probabilitatea ca un chibrit aruncat aleatoriu să atingă o linie verticală. Primul pas este să explicităm acest eveniment, adică să-l împărțim în două evenimente mai simple. Astfel, putem spune că, pentru a arunca aleatoriu un chibrit, mai întâi alegem un număr random reprezentând distanța dintre mijlocul chibritului și cea mai apropiată linie verticală, după care alegem un număr random reprezentând unghiul ascuțit pe care chibritul îl formează cu dreapta verticală care trece prin mijlocul său.
Iată și o animație care simulează modul în care este generat un chibrit random. Dați un click pentru a alege ul, un alt click pentru a-l fixa pe și încă unul pentru a o lua de la capăt.
Probabilitatea ca să primească o anumită valoare fixată de noi este practic inversul lungimii intervalului, adică Similar, probabilitatea ca să primească o anumită valoare este Cum cele două evenimente sunt independente, probabilitatea ca întreaga pereche să aibă o anumită valoare este egală cu produsul dintre și adică
Acum, trebuie să găsim o relație în funcție de și care să ne spună dacă chibritul nostru intersectează într-adevăr vreo linie verticală. Observăm ușor că intersecția are loc doar dacă este mai mic sau egal cu distanța de la capătul stâng al chibritului la verticala care trece prin mijlocul său. Cea din urmă poate fi exprimată drept
Tot ce ne mai rămâne de făcut este să evaluăm funcția obținută anterior, în toate punctele cu proprietatea că și după care să însumăm aceste valori. Exact ăsta e genul de lucru pe care-l face o integrală (dublă):
Sfârșit! Dacă aveți vreo întrebare despre ce am discutat în articolul de astăzi, o puteți adresa mai jos, într-un comentariu. Iar dacă vi s-a părut un articol interesant, nu uitați să-i dați un share pe FaceBook Și, Happy Pi Day!