Benchmarking, tra Python, Ruby, Nodejs, Golang, Java e Rust, per la risoluzione del valore di $\Pi$ utilizzando il metodo Monte Carlo.
Devono essere installati:
- Python ver. 3.12.4 o successiva
- Ruby ver. 3.3.5 o successiva
- Nodejs ver. 20.18.0 o successiva
- Golang ver. 1.22.4 o successiva
- Rust ver. 1.82.0 o successiva
- Java ver. 1.8.0_422 o successiva
Utilizzando Python, Ruby, Nodejs, Golang, Java e Rust sono stati implementati quattro script con lo stesso algoritmo di risoluzione del valore di
E' possibile eseguire tutti gli script in seguenza, tramite lo script run.sh <numero interazioni>
o run.bat <numero interazioni>
, oppure eseguirli singolarmente con:
-
Python
export PI_SIMULATIONS=<numero interazione> python3 ./PY/main.py
-
Ruby
export PI_SIMULATIONS=<numero interazione> ruby ./RB/main.rb
-
Nodejs
export PI_SIMULATIONS=<numero interazione> node ./JS/index.js
-
Go
go build -o ./GO/main ./GO/main.go export PI_SIMULATIONS=<numero interazione> ./GO/main
-
Rust
cd RS cargo build --release -q export PI_SIMULATIONS=<numero interazione> ./target/release/main
-
Java
cd JV javac ./Main.java export PI_SIMULATIONS=<numero interazione> java Main && cd .. ``` ```
Per eseguire ./hyperfine.sh
, si deve installare il binario: Hyperfine installation
Utilizzando un Intel® Core™ i5-6500 e 32Gb i risultati, misurati in secondi, sono:
ver. | 1.000 | 5.000 | 1.000.000 | 5.000.000 | |
---|---|---|---|---|---|
Python | 3.12.4 | 0,00017 [739,13%] |
0,000806 [680,92%] |
0,171172 [1022,83%] |
0,871845 [936,66%] |
Ruby | 3.3.5 | 0,003380644 [14698,45%] |
0,01664606 [14062,85%] |
3,185276161 [19033,5%] |
16,004425921 [17194,31%] |
Nodejs | 20.18.0 | * | 0,001 [844,81%] |
0,03 [179,26%] |
0,135 [145,03%] |
Golang | 1.22.4 | 0,000023 [100%] |
0,000132 [111,51%] |
0,022069 [131,87%] |
0,119983 [128,9%] |
Rust | 1.82.0 | 0,000030641 [133,22%] |
0,000118369 [100%] |
0,016735104 [100%] |
0,093079769 [100%] |
Java | 1.8.0_422 | 0,001604 [6973,91%] |
0,004325 [3653,82%] |
0,050392 [301,11%] |
0,224448 [241,13%] |
Utilizzando un Apple® M2 e 16Gb i risultati, misurati in secondi, sono:
ver. | 1.000 | 5.000 | 1.000.000 | 5.000.000 | |
---|---|---|---|---|---|
Python | 3.12.4 | 0,000101 [721,43%] |
0,000489 [444,55%] |
0,100177 [778,62%] |
0,529444 [788,34%] |
Ruby | 3.3.5 | 0,000484 [3457,15%] |
0,002548 [2316,37%] |
0,545488 [4239,77%] |
2,631342 [3918,02%] |
Nodejs | 20.18.0 | * | 0,001 [909,1%] |
0,036 [279,81%] |
0,11 [163,79%] |
Golang | 1.22.4 | 0,000014 [100%] |
0,000182 [165,46%] |
0,012866 [100%] |
0,06716 [100%] |
Rust | 1.82.0 | 0,000025167 [179,77%] |
0,00011 [100%] |
0,022051792 [171,4%] |
0,115934333 [172,63%] |
Java | 17.0.12 | 0,000559 [3992,86%] |
0,000761 [691,82%] |
0,042703 [331,91%] |
0,221541 [329,88%] |
* Nodejs non misura frazioni del millisecondo
Il metodo "Monte Carlo" è una stategia di risoluzione di problemi che utilizza la statistica: se la probabilità di un certo evento è P possiamo simulare in maniera random questo evento e ottenere P facendo:
P = (numero di volte in cui il nostro evento è avvenuto)/(simulazioni totali)
.
Vediamo come applicare questa strategia per ottenere un'approssimazione di pi greco
Data un cerchio di raggio 1, esso può essere inscritto in un quadrato di lato 2.
Guardiamo solamente ad uno spicchio del cerchio:
In questo modo sappiamo che l'area del quadrato in blu è 1 e l'area dell'area rossa invece è
Se generiamo N numeri random all'interno del quadrato il numero di punti che cadono nel cerchio M diviso il numero totale di numeri generati N dovrà approssimare appunto l'area del cerchio e quindi
In sostanza otterremo
Maggiore sarà il numero di punti generati più precisa sarà l'approssimazione di
Chiaramente ogni esecuzione darà un valore leggermente diverso ma aumentando il numero di punti possiamo "stabilizzare" un numero di cifre decimali a piacere. Osserviamo come l'implementazione del random sia determinante per questo calcolo: se i double non fossero generati in maniera uniforme tra 0 e 1 il valore di pi risulterebbe sbagliato!