Недавно я нашел презентацию о F # для программистов на Python, и после просмотра ее решил реализовать решение головоломки ant "самостоятельно.
Существует ant, который может перемещаться по плоской сетке. ant может перемещать одно пространство за раз влево, вправо, вверх или вниз. То есть из ячейки (x, y) ant может перейти в ячейки (x + 1, y), (x-1, y), (x, y + 1) и (x, y-1), Точки, где сумма цифр координат x и y больше 25, недоступны для ant. Например, точка (59,79) недоступна, потому что 5 + 9 + 7 + 9 = 30, что больше 25. Вопрос: сколько точек может иметь доступ ant, если он начинается с (1000, 1000), включая (1000, 1000) себя?
Я выполнил свое решение в 30 строках OCaml в начале и попробовал:
$ ocamlopt -unsafe -rectypes -inline 1000 -o puzzle ant.ml
$ time ./puzzle
Points: 148848
real 0m0.143s
user 0m0.127s
sys 0m0.013s
Приятный, мой результат такой же, как у leonardo implementation, в D и С++. Сравнивая с реализацией leonardo С++, версия OCaml работает примерно в 2 раза медленнее, чем С++. Это нормально, учитывая, что leonardo использовал очередь для удаления рекурсии.
Я тогда перевел код на F #... и вот что я получил:
[email protected] /g/Tmp/ant.fsharp
$ /g/Program\ Files/FSharp-2.0.0.0/bin/fsc.exe ant.fs
Microsoft (R) F# 2.0 Compiler build 2.0.0.0
Copyright (c) Microsoft Corporation. All Rights Reserved.
[email protected] /g/Tmp/ant.fsharp
$ ./ant.exe
Process is terminated due to StackOverflowException.
Quit
[email protected] /g/Tmp/ant.fsharp
$ /g/Program\ Files/Microsoft\ F#/v4.0/Fsc.exe ant.fs
Microsoft (R) F# 2.0 Compiler build 4.0.30319.1
Copyright (c) Microsoft Corporation. All Rights Reserved.
[email protected] /g/Tmp/ant.fsharp
$ ./ant.exe
Process is terminated due to StackOverflowException
Переполнение стека... с обеими версиями F #, которые у меня есть на моей машине... Из любопытства я тогда взял сгенерированный двоичный файл (ant.exe) и запустил его в Arch Linux/Mono:
$ mono -V | head -1
Mono JIT compiler version 2.10.5 (tarball Fri Sep 9 06:34:36 UTC 2011)
$ time mono ./ant.exe
Points: 148848
real 1m24.298s
user 0m0.567s
sys 0m0.027s
Удивительно, но он работает под Mono 2.10.5 (т.е.) - но это занимает 84 секунды, т.е. в 587 раз медленнее, чем OCaml - oops.
Итак, эта программа...
- работает под OCaml
- вообще не работает в .NET/F #
- работает, но очень медленно, в режиме Mono/F #.
Почему?
РЕДАКТИРОВАТЬ: Странность продолжается - с помощью "--optimize + --checked-" проблема исчезает, , но только в ArchLinux/Mono; под Windows XP и Windows 7/64bit, даже оптимизированная версия переполнения двоичного стека.
Final EDIT: я сам выяснил ответ - см. ниже.