J'essaie l'informatique Ackermann(4,1)
et il y a une grande différence de performance entre les différents langages/compilateurs. Voici les résultats obtenus sur mon Core i7 3820QM, 16G, Ubuntu 12.10 64bit ,
C : 1.6s , gcc -O3
(avec gcc 4.7.2)
int ack(int m, int n) {
if (m == 0) return n+1;
if (n == 0) return ack(m-1, 1);
return ack(m-1, ack(m, n-1));
}
int main() {
printf("%d\n", ack(4,1));
return 0;
}
OCaml : 3.6s , ocamlopt
(avec ocaml 3.12.1)
let rec ack = function
| 0,n -> n+1
| m,0 -> ack (m-1, 1)
| m,n -> ack (m-1, ack (m, n-1))
in print_int (ack (4, 1))
Standard ML : 5.1s mlton -codegen c -cc-opt -O3
(avec mlton 20100608)
fun ack 0 n = n+1
| ack m 0 = ack (m-1) 1
| ack m n = ack (m-1) (ack m (n-1));
print (Int.toString (ack 4 1));
Raquette : 11.5s racket
(avec racket v5.3.3)
(require racket/unsafe/ops)
(define + unsafe-fx+)
(define - unsafe-fx-)
(define (ack m n)
(cond
[(zero? m) (+ n 1)]
[(zero? n) (ack (- m 1) 1)]
[else (ack (- m 1) (ack m (- n 1)))]))
(time (ack 4 1))
Haskell : inachevé tué par le système après 22s ghc -O2
(avec ghc 7.4.2)
Haskell : 1.8s ajhc
(avec ajhc 0.8.0.4)
main = print $ ack 4 1
where ack :: Int -> Int -> Int
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))
La version Haskell est la seule qui ne se termine pas correctement parce qu'elle prend trop de mémoire. Elle gèle ma machine et remplit l'espace de swap avant de se faire tuer. Que puis-je faire pour l'améliorer sans fuglifier lourdement le code ?
EDIT : J'apprécie certaines des solutions asymptotiquement plus intelligentes, mais elles ne sont pas exactement ce que je demande. Il s'agit plus de voir si le compilateur traite certains motifs de manière raisonnablement efficace (pile, appels de queue, unboxing, etc.) que de calculer la fonction d'ackermann.
EDIT 2 : Comme l'ont souligné plusieurs réponses, il semble que ce soit un bogue dans les versions récentes de GHC . J'essaie le même code avec AJHC et obtenir de bien meilleures performances.
Merci beaucoup :)