=KRoN=>Итак, O'Caml.=KRoN=>С исходным текстом мудрить не стал.=KRoN=>
=KRoN=>let rec a n x y =
=KRoN=> match (n, y) with
=KRoN=> (0, y) -> x+1
=KRoN=> | (1, 0) -> x
=KRoN=> | (2, 0) -> 0
=KRoN=> | (3, 0) -> 1
=KRoN=> | (n, 0) -> 2
=KRoN=> | (n, y) -> (a (n-1) (a n x (y-1)) x)
=KRoN=> ;;
=KRoN=>print_int(a 3 8 8);
=KRoN=>print_newline();;
=KRoN=>
[/html_font]
=KRoN=>Компиляция - ocamlopt.exe -S -inline 100 -o akkr.exe -ccopt /F32768000 akkr.ml=KRoN=>Как видим, стека хватает в 10 раз меньшего, чем на VC7.
И этому есть объснение - смотри ниже.
=KRoN=>Время работы программы - 2.23 сек!
=KRoN=>При чём он даже не пытался делать внешнюю раскрутку функции.=KRoN=>Вот, если кому интересно, ассемблерный код функции:
Вот здесь я и прокомментирую.
=KRoN=>[html_font size=+0][html_font color=blue]
=KRoN=>_Akkr_a_49:
=KRoN=> sub esp, 8 - налицо отсутствие оформления фрэйма
стэка - в спорах на этом форуме я не
раз упоминал, что в современных языках
вызов процедуры одно из самых дорогих
удовольствий - фрэйм для локальных
переменных, передача параметров
через стек и т.д. Здесь произведена
резервация под две временные
переменные. Надо еще сказать, что
параметры передаются через регистры -
n - eax, x - ebx, y - ecx. Результат
возвращается на eax.
=KRoN=>L106: Запомните эту метку!!!!
=KRoN=> cmp eax, 7 Все константы и вычисления сдвинуты
по формуле 2*n+1 иниыми словами это
сравнение cmp eax,3
=KRoN=> ja L101 есла n больше 3, то это общий случай
=KRoN=> mov edx, eax иначе преобразуем это в индекс для
косвенного перехода - таким образом
закодирована первая часть match
=KRoN=> sar edx, 1
=KRoN=> jmp [edx * 4 + L107]
=KRoN=> .DATA
Это собственно таблица
косвенной адресации
=KRoN=>L107 DWORD L105 n == 0
=KRoN=> DWORD L104 n == 1
=KRoN=> DWORD L103 n == 2
=KRoN=> DWORD L102 n == 3
=KRoN=> .CODE
=KRoN=>L105:
=KRoN=> add ebx, 2 x + 1
=KRoN=> mov eax, ebx вернуть на eax
=KRoN=> add esp, 8 подровнять стек
=KRoN=> ret
=KRoN=>L104:
=KRoN=> cmp ecx, 1 сравнение y == 0
=KRoN=> jne L10
=KRoN=> mov eax, ebx x
=KRoN=> add esp, 8
=KRoN=> ret
=KRoN=>L103:
=KRoN=> cmp ecx, 1 y == 0
=KRoN=> jne L101
=KRoN=> mov eax, 1 вернуть 0
=KRoN=> add esp, 8
=KRoN=> ret
=KRoN=>L102:
=KRoN=> cmp ecx, 1 y == 0
=KRoN=> jne L101
=KRoN=> mov eax, 3 вернуть 1
=KRoN=> add esp, 8
=KRoN=> ret
=KRoN=>L101: общий случай
=KRoN=> cmp ecx, 1 y == 0
=KRoN=> je L100
=KRoN=> mov DWORD PTR 0[esp], eax внимание, сохраним n
=KRoN=> mov DWORD PTR 4[esp], ebx и х во временные
переменные
=KRoN=> add ecx, -2 y - 1
=KRoN=> call _Akkr_a_49 вызовем функцию для вычисления
a n x ( y - 1 ) - внутренний
вызов.
=KRoN=>L108:
А вот здесь начинается второе
место, где объектный верблюд
выигрывает. ВНИМАНИЕ.
Вместо вызова функции еще раз
верблюд подготовил параметры
на регистрах и перешел на ту
метку, которую я вам советовал
завпомнить - сразу после
sub esp,8 - тем самым экономия
сразу в двух местах - нет
операции вызова - она заменена
переходом (нет работы со стеком
и т.д.) и еще - переиспользова-
ние временных переменных без их
дополнительного переразмещнния
на стеке!
=KRoN=> mov ebx, eax результат на eax - поместим
его вторым параметром - как x
=KRoN=> mov eax, DWORD PTR 0[esp] востановим n
=KRoN=> add eax, -2 и отнимем 1 - т.е. мы
имеем n - 1 первым
параметром
=KRoN=> mov ecx, DWORD PTR 4[esp] а бывший x передадим пос-
ледним
=KRoN=> jmp L106 А вот и тот самый переход
вместо вызова!!!!!
=KRoN=>L100:
=KRoN=> mov eax, 5 здесь возратим 2
=KRoN=> add esp, 8
=KRoN=> ret
[/html_font]
[ слишком длинный топик - автонарезка ]