Bonjour, le monde ! Ceci est mon premier article, et il est exclusivement utilisé pour tester les fonctionnalités de ce site.
Voici quelques extraits de code dans différents langages qui calculent le Problème de Bâle :
Pour commencer,
Python
def pi_squared_over_6(N: int) -> float:
return sum(x**(-2) for x in range(1,N))
Rust
fn pi_squared_over_6(N: u64) -> f64 {
(1..N).map(|x| 1.0 / ((x*x) as f64)).sum()
}
Haskell
piSquaredOver6 :: Integer -> Double
-- pas de N majuscule en Haskell :(
piSquaredOver6 n = sum $ map (\x -> 1 / fromIntegral (x * x)) [1..n]
C
double pi_squared_over_6(unsigned int N) {
double sum = 0.0;
for (int i = 1; i < N; i++) {
sum += 1.0 / (i*i);
}
return sum;
}
Quelle est votre solution préférée ?
Performance
Voyons comment elles se comparent en performance sur un M1 Pro, pour .
Langage | Temps (ms, ) |
---|---|
Rust (parallélisé) | |
Rust (–release) | |
C (-O3) | |
Haskell (-O3) | |
Python (3.10) |
Améliorer Python
Le code Python a pris un temps absurde à s’exécuter, alors améliorons-le en profitant de numpy, qui appelle du code C vectorisé.
import numpy as np
def pi_squared_over_6(N: int) -> float:
x = np.ones(N)
r = np.arange(1,N)
sq = np.square(r)
div = np.divide(x, sq)
return float(np.sum(div))
Un peu mieux, mais lorsque je vérifie btm
, la consommation excessive de mémoire suggère que la plupart du travail consiste à déplacer des milliards de flottants, et non à effectuer les calculs. Essayons de diviser cela en morceaux :
def pi_squared_over_6(N: int) -> float:
CHUNKS = 25000
SIZE = N // CHUNKS
s = 0.0
x = np.ones(N // CHUNKS - 1)
for i in range(CHUNKS):
N_tmp = i * SIZE
r = np.arange(N_tmp + 1, N_tmp + SIZE)
sq = np.square(r)
div = np.divide(x, sq)
s += np.sum(div)
# libérer la mémoire
del sq
del div
del r
return s
Beaucoup mieux ! Maintenant, il s’exécute en moins de 2 secondes !