Я пытаюсь вычислить Ackermann(4,1)
, и есть большая разница в производительности между разными языками/компиляторами. Ниже приведены результаты на моем Core i7 3820QM, 16G, Ubuntu 12.10 64bit,
C: 1.6s, gcc -O3
(с 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
(с окамлом 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: 5.1s mlton -codegen c -cc-opt -O3
(с 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));
Ракетка: 11,5 с 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: незавершенный, убитый системой после 22s ghc -O2
(с ghc 7.4.2)
Haskell: 1,8 с ajhc
(с 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))
Версия Haskell является единственной, которая не может завершиться должным образом, потому что она занимает слишком много памяти. Он замерзает мою машину и заполняет пространство подкачки перед тем, как его убили. Что я могу сделать, чтобы улучшить его без серьезного исправления кода?
EDIT. Я ценю некоторые из асимптотически умных решений, но они не совсем то, о чем я прошу. Это больше похоже на то, обрабатывает ли компилятор определенные шаблоны достаточно эффективным способом (стек, хвостовые вызовы, распаковка и т.д.), Чем вычисление функции ackermann.
EDIT 2. Как было отмечено несколькими ответами, это выглядит как ошибка в последних версиях GHC. Я пробую тот же код с AJHC и получаю гораздо лучшую производительность.
Большое спасибо:)