为什么Python2.x中的math.factorial比3.x慢得多?

为什么Python2.x中的math.factorial比3.x慢得多?,python,performance,python-3.x,python-2.x,factorial,Python,Performance,Python 3.x,Python 2.x,Factorial,我在我的机器上得到以下结果: Python 3.2.2 (default, Sep 4 2011, 09:51:08) [MSC v.1500 32 bit (Intel)] on win 32 Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> timeit.timeit('factorial(10000)', 'from

我在我的机器上得到以下结果:

Python 3.2.2 (default, Sep  4 2011, 09:51:08) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit('factorial(10000)', 'from math import factorial', number=100)
1.9785256226699202
>>>

Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit('factorial(10000)', 'from math import factorial', number=100)
9.403801111593792
>>>
我认为这可能与int/long转换有关,但在2.7中,
factorial(10000L)
并没有更快


1121用于(i=1;I10000!-你知道这个数字有多大吗?@duffymo,这并不能解释速度的差异可能是Python 3比Python 2快。如果是相反的话,这将是一个有趣的问题。我很清楚这个数字有多大。我想它可能会生成
int
s,然后必须重新转换让它们相乘,但这并不能解释问题。我曾看到报告称,3.x版本中某些东西的速度更快,2.x版本中某些东西的速度更快,但一个接近五分之一的差异是非常不寻常的。如果你对此感到好奇,你应该深入了解其来源:)有趣的是,也有点遗憾的是,尽管表面上是用C实现的,但Python 2.x中的
math.factorial
似乎并不比纯Python中简单的
for
循环快多少。使用Python长整数的开销似乎会消耗掉C中循环所能获得的任何收益。正如链接的Pyt中所评论的那样亲爱的bugtracker thread,如果你真的想要这类东西的性能,请使用
gmpy
@JohnY。除了所选的算法之外,我不确定你选择的哪个实现是重要的。无论你是用汇编语言编写还是用高级语言编写,使用朴素的算法都不可能获得良好的性能。@agf:我不是ex我猜想一个朴素的算法比另一种语言中的同一个朴素算法具有更好的big-O复杂度。我仍然认为
math.factorial与纯Python朴素算法相比,甚至没有太多的常数因子改进,这有点滑稽和悲哀。@JohnY有多快r同样未优化的naive算法的非Python C实现会是什么?您假设它会快得多,并将其作为C级Python对象性能差的证据,但没有证明这一点。@agf:我没有任何假设,也没有说C级Python对象性能差。我甚至不知道“同样未优化”的实现是,因为如果要复制完整的功能,就必须实现bignums。令我惊讶的是,Python开发人员决定在
math
模块中包含一个比纯Python函数稍好的函数,该模块的目的是(在所有其他方面似乎都是)纯C例程的薄包装(阶乘不是)。
1121 for (i=1 ; i<=x ; i++) {
1122     iobj = (PyObject *)PyInt_FromLong(i);
1123     if (iobj == NULL)
1124         goto error;
1125     newresult = PyNumber_Multiply(result, iobj);
1126     Py_DECREF(iobj);
1127     if (newresult == NULL)
1128         goto error;
1129     Py_DECREF(result);
1130     result = newresult;
1131 }
1229 * factorial(n) is written in the form 2**k * m, with m odd. k and m are 1230 * computed separately, and then combined using a left shift.