2010-09-27 56 views
1

由于PHP对我来说比较简单,所以我希望能够对其中的算法进行基准测试以获得乐趣,并且我选择了阶乘因子。PHP中的算法基准没有意义吗?

与迭代方法相比,递归函数在速度上完全没有达到80!,并且在迭代有稳定线条时它逐渐暴涨,实际上它是这样的(x = factorial,y = seconds) :

http://i52.tinypic.com/2a9s7z4.png

但在C/Java的(我只是执行测试)显示了相同的结果是只有1-5折,从海誓山盟,几乎相同的速度。

在脚本语言中以这种方式对算法进行基准测试毫无用处吗?

编辑:对于NullUserException:

function factrec($x) { 
    if($x <= 1) { 
     return $x; 
    } else { 
     return $x * factrec($x - 1); 
    } 
} 
+0

要实现阶乘错的,如果递归版本是比迭代一个糟糕得多。 – NullUserException 2010-09-27 23:05:00

+0

@NullUserException:我编辑了我的帖子,向您展示了它的一般代码。我设置了输出缓冲(ob_start()),并在回显10000000结果和迭代后刷新它。 – John 2010-09-27 23:07:03

+0

如果我记得,PHP中的递归非常缓慢,所以这可以解释这里的区别。 – 2010-09-27 23:12:03

回答

4

用脚本语言对算法进行基准测试绝对没有意义。在做完基准测试之后,您将在PHP中使用哪个阶乘实现? (假设你由于某种原因不能使用内置的那个)。

对于具有明显不同于要实现该算法的特性的语言的基准来说,没有多大意义。在这里,函数调用和PHP中的if语句的相对成本显着地歪曲了结果(或者这是我最好的猜测)。如果你仔细理解为什么会发生这种情况并避免这种情况发生,它仍然可以取得丰硕成果:如你所注意到的,差异会更加夸张。归结起来,如果用目标语言编写它或者解决这些差异更容易。

算法的复杂性的简单计算应该足以决定使用哪一个,或者至少缩小选择范围。


麦克Axiak在评论中指出的,你是不是即使在这里测试不同的算法,如果正在测试相同的算法的两种不同的实现:保持一个正在运行的产品在in1。以与目标不同的语言来做这件事几乎总是毫无意义。

+0

而且应该注意的是,如果您选择迭代或递归实现,算法复杂性不会改变。 – 2010-09-27 23:15:14

+0

@Mike Axiak。那是个很好的观点。我甚至会说明你的意思,并说在这种情况下他们甚至不是不同的算法。 – aaronasterling 2010-09-27 23:17:00

+0

我喜欢所有这些答案。 (脚本语言)中的每个元素都增加了脚本的复杂性以及它的工作原理,这可能会掩盖算法的真实性能,我将从现在开始对php和php函数进行基准测试,并且使用对其他人来说更强大的东西。 – John 2010-09-27 23:31:06

1

在我看来,如果我是测试算法本身我会去C/C++,获得“原始动力”它可以在最佳条件下给予。另一方面,如果我必须选择哪种算法在某种条件下效果最好,那么我会尝试在最好的情况下复制这样的条件。它是否必须放在PHP应用程序中?让我们用PHP提供的结构来测试它。它需要使用STL容器吗?我会在这种情况下进行测试,而不仅仅是数组。在真实条件下进行恕我直通测试是获得有意义结果的关键。得到这样的结果后,另一件好事就是调整这些条件(只要你可以在项目中改变它们),看看你会得到什么样的效果,找到最佳条件 - 算法夫妇。

+0

我相信OP的意图是对_脚本语言_(在本例中为PHP)进行基准测试,以及它们如何实现计算密集型算法。 – adib 2010-09-27 23:12:50

+0

我认为这是一个问题:“在脚本语言中以这种方式对算法进行基准测试毫无用处?”我的意见是:不,如果那你必须用这些语言来使用它们。 :) – 2010-09-27 23:17:33

1

递归与迭代实现应该对特定算法的渐近行为没有实际影响。在某些语言(scala,Scheme,Lua,Standard ML,Mozart/Oz,erlang)中,这两者实际上可以写成完全相同的语言。即,以下方案代码:

(define factorial 
    (lambda (n acc) 
    (if (= n 0) acc 
     (factorial (- n 1) (* n acc))))) 
(factorial 5 1) 
-> 120 

不会使用堆栈,因此执行与迭代方法相同的操作。 (这被称为尾部呼叫优化,并且当您执行尾递归时使用这种语言来调用。)

+0

+1,我期待在我的Java基准实现中测量尾递归以测试PHP的结果,但不幸的是我的jvm不支持它。 – John 2010-09-27 23:32:50

1

基准测试永远没有意义。如果你有一些代码,用任何语言编写,对于你的应用程序来说太慢了,你可以找出瓶颈。看着这些瓶颈,你寻找解决方案。一个解决方案可能是使用算法的不同公式,甚至用不同的语言重写。

我不知道关于PHP的一些东西,所以我不知道递归在那个环境中是否处理得很好,但是我有这样的印象,它不是执行重型重复数学的好选择......

1

由于递归性很差,您正在运行PHP的问题。人们通常不会选择PHP来做这件事。总是选择最适合的工具。

1

考虑到练习的重点是好玩的,它不能毫无意义!但是试图让PHP执行递归计算可能表明您准备尝试使用函数式编程语言。你见过Haskell吗?尾巴呼叫优化,任何人?

来吧,加入黑暗的一面。

+0

+1,你让我想到用这样的语言来实现我的小基准。这将是一个很好的数学练习。 – John 2010-09-27 23:31:49

+0

一个“不错的数学练习” - Mu-hahahaha! http://www.haskell.org/haskellwiki/The_Fibonacci_sequence – wlangstroth 2010-09-27 23:38:04

1

Java和C比PHP快几个数量级。
您需要大幅增加输入尺寸以查看结果。另外,正如Aaron McSmooth所说,使用除计划使用的语言之外的其他语言对算法进行基准测试毫无意义。

我不确定,但我怀疑PHP没有调用优化。 无论如何,使用尾递归函数应该提高你的递归函数的表现颇有几分:

function factorial($n, $product) { 
    if ($n < 1) 
     return $product; 
    else 
     return factorial($n-1, $product*$n); 
} 

print(factorial(80, 1)); 
+0

您可以确定:PHP不会执行尾部调用优化。但是,你可以蹦床。 – wlangstroth 2010-09-27 23:44:06

+0

咦,该函数产生这些结果(用在阶乘增加):'ITER:1.315s REC:4.069s ITER:1.861s REC:7.32s ITER:2.951s REC:13.863s ITER:4.993s rec:26.769s iter:9.569s rec:53.639s'由于某种原因,速度较慢。 – John 2010-09-29 02:39:14