nic*_*man 6 ruby performance tail-recursion rubinius
我有这两个gcd函数的实现:
def gcd1(a,b)
if a==b
a
elsif a>b
if (a%b)==0
b
else
gcd1(a%b,b)
end
else
if (b%a)==0
a
else
gcd1(a,b%a)
end
end
end
def gcd2(a,b)
if(a==b)
return a
elsif b>a
min,max=a,b
else
min,max=b,a
end
while (max%min)!=0
min,max=max%min,min
end
min
end
Run Code Online (Sandbox Code Playgroud)
函数gcd1是尾递归的,而gcd2使用while循环.
我已经验证了rubinius通过对因子函数进行基准测试来进行TCO,只有基数函数,基准测试显示递归版本和迭代版本是"相同的"(我使用的是基准测试版).
但是对于上述情况,基准测试显示gcd1比gcd2快至少两倍(递归速度是迭代速度的两倍,甚至更快).
我用来进行基准测试的代码如下:
Benchmark.ips do |x|
x.report "gcd1 tail recursive" do
gcd1(12016,18016)
end
x.report "gcd2 while loop" do
gcd2(12016,18016)
end
x.compare!
end
Run Code Online (Sandbox Code Playgroud)
结果 :
Warming up --------------------------------------
gcd1 tail recursive 47.720k i/100ms
gcd2 while loop 23.118k i/100ms
Calculating -------------------------------------
gcd1 tail recursive 874.210k (± 7.1%) i/s - 4.343M
gcd2 while loop 299.676k (± 6.6%) i/s - 1.503M
Comparison:
gcd1 tail recursive: 874209.8 i/s
gcd2 while loop: 299676.2 i/s - 2.92x slower
Run Code Online (Sandbox Code Playgroud)
我正在运行Arch linux x64,处理器i5-5200 2.2 GHZ四核.
ruby实现是Rubinius 3.40.
那么递归如何比循环更快?
只是说斐波纳契具有相同的情况:尾递归版本至少是循环版本的两倍,我用于斐波那契的程序:http://pastebin.com/C8ZFB0FR
在您使用的示例中,只需要 3 次调用/循环即可得到答案,所以我认为您实际上没有测试正确的东西。尝试使用两个连续的斐波那契数(例如第 2000 个和第 2001 个),结果应该不会有太大差异。
(抱歉,我还没有资格发表评论)。
编辑:我终于成功安装了 rubinius 的[一部分],并成功地重新创建了您所指的现象。这不是关于递归,而是关于多重赋值。如果你改变
while n>0
a,b=b,a+b
n-=1
end
Run Code Online (Sandbox Code Playgroud)
到
while n>0
t=a
a=b
b=t+b
n-=1
end
Run Code Online (Sandbox Code Playgroud)
while 循环版本应该执行得更快(一点)。原来的GCD程序也是如此,即替换
min,max=max%min,min
Run Code Online (Sandbox Code Playgroud)
和
t=min
min=max%t
max=t
Run Code Online (Sandbox Code Playgroud)
就是这样。
ruby-2.1 的情况并非如此,即 while 循环似乎更快,只是以您提供的形式。
希望有帮助!
| 归档时间: |
|
| 查看次数: |
282 次 |
| 最近记录: |