I am trying to calculate Ackermann(4,1) , and there is a big performance difference between different languages / compilers. Below are the results on my Core i7 3820QM, 16G, Ubuntu 12.10 64bit ,
C: 1.6s , gcc -O3 (with 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 (with okaml 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))
ML standard: 5.1s mlton -codegen c -cc-opt -O3 (with mlton 20100608)
fun ack 0 n = n+1 | ack m 0 = ack (m-1) 1 | ack mn = ack (m-1) (ack m (n-1)); print (Int.toString (ack 4 1));
Racket: 11.5 with racket (with racket v5.3.3)
(require racket/unsafe/ops) (define + unsafe-fx+) (define - unsafe-fx-) (define (ack mn) (cond [(zero? m) (+ n 1)] [(zero? n) (ack (- m 1) 1)] [else (ack (- m 1) (ack m (- n 1)))])) (time (ack 4 1))
Haskell: unfinished , killed by the system after 22s ghc -O2 (with ghc 7.4.2)
Haskell: 1.8 with ajhc (with 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 mn = ack (m-1) (ack m (n-1))
The Haskell version is the only one that cannot complete properly because it takes up too much memory. He freezes my car and fills the swap space before they kill him. What can I do to improve it without seriously fixing the code?
EDIT . I appreciate some of the asymptotically smart solutions, but they are not quite what I ask. This is more like whether the compiler processes certain patterns in an efficient way (stack, tail calls, unpacking, etc.) than evaluating the ackermann function.
EDIT 2 . As noted by several answers, this looks like a bug in recent versions of GHC . I try the same code with AJHC and get much better performance.
Thank you very much:)