【发布时间】:2011-11-24 05:06:26
【问题描述】:
我最近发现了一个关于F# for Python programmers的演示,看了之后,我决定自己实现一个“蚂蚁谜题”的解决方案。
有一只蚂蚁可以在平面网格上四处走动。蚂蚁每次可以向左、向右、向上或向下移动一个空间。也就是说,蚂蚁可以从单元格 (x, y) 到单元格 (x+1, y)、(x-1, y)、(x, y+1) 和 (x, y-1)。 x 和 y 坐标的数字总和大于 25 的点对于蚂蚁来说是不可接近的。例如,点 (59,79) 是不可访问的,因为 5 + 9 + 7 + 9 = 30,大于 25。问题是:如果从 (1000, 1000) 开始,蚂蚁可以访问多少个点,包括 (1000, 1000) 本身?
我在 OCaml first 的 30 行中实现了我的解决方案,并尝试了它:
$ ocamlopt -unsafe -rectypes -inline 1000 -o puzzle ant.ml
$ time ./puzzle
Points: 148848
real 0m0.143s
user 0m0.127s
sys 0m0.013s
很好,我的结果和leonardo's implementation, in D and C++的结果一样。与 Leonardo 的 C++ 实现相比,OCaml 版本的运行速度比 C++ 慢约 2 倍。没关系,因为 Leonardo 使用队列来移除递归。
然后我 translated the code to F# ... 这就是我得到的:
Thanassis@HOME /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.
Thanassis@HOME /g/Tmp/ant.fsharp
$ ./ant.exe
Process is terminated due to StackOverflowException.
Quit
Thanassis@HOME /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.
Thanassis@HOME /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 秒,即比 OCaml 慢 587 倍 - 哎呀。
所以这个程序...
- 在 OCaml 下运行良好
- 在 .NET/F# 下根本不起作用
- 在 Mono/F# 下可以工作,但速度很慢。
为什么?
编辑:奇怪的继续 - 使用“--optimize+ --checked-”使问题消失,但仅限于 ArchLinux/Mono;在Windows XP和Windows 7/64bit下,即使是优化版的二进制栈也会溢出。
最终编辑:我自己找到了答案 - 见下文。
【问题讨论】:
-
@CarstenKönig Expert F# 2.0 说:“...使用 --optimize 编译您的最终代码,它对您的代码应用最大优化。这也是 fsc.exe 的默认优化设置。”在 pg164 上。这是否意味着 ttsiodras 已经启用了所有优化?
-
对 walk 的递归调用不在尾部位置。这就解释了为什么会出现堆栈溢出。为什么在其他情况下不会出现堆栈溢出,可能是因为在这些系统上堆栈设置得更大,或者是因为 mono JIT 和 OCAML 编译器做了一些非常聪明的事情。
-
我认为这是一个很好的问题,但它被关闭太糟糕了。对“请明确说明您要问的内容”的顺序的初步评论将解决此问题。或者,至少它应该在 ttsiodras 修复之后重新打开。
-
我同意这是一个非常有趣的问题,并且正在投票重新打开它。关于这个主题可以说的比这个评论的空间允许的要多得多......
-
听起来你找到了答案。为什么要赏金?还有什么问题?
标签: f# ocaml stack-overflow tail-recursion