2012-03-22 15 views
31

puedo obtener los siguientes resultados en mi máquina:¿Por qué math.factorial es mucho más lento en Python 2.x que en 3.x?

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 
>>> 

pensé que esto podría tener algo que ver con la conversión long int /, pero factorial(10000L) no es más rápido en 2.7.

+0

10,000! - ¿Te das cuenta de cuán grande es ese número? http://gimbo.org.uk/texts/ten_thousand_factorial.txt – duffymo

+7

@duffymo Eso no explica la diferencia de velocidad –

+0

No estoy tratando de explicarlo. Me pregunto si el OP es consciente, eso es todo. La conversión int/long apenas parece relevante. ¿Dónde está tu respuesta, isbadawi? – duffymo

Respuesta

43

Python 2 utiliza el naive factorial algorithm:

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 } 

Python 3 utiliza la divide-and-conquer factorial algorithm:

 
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. 

Véase el Python Bugtracker issue para la discusión. Gracias DSM por señalar eso.

+11

Consulte http://bugs.python.org/issue8692 para la discusión. – DSM

+0

Curiosamente, y algo triste, a pesar de que se implementó ostensiblemente en C, 'math.factorial' en Python 2.x no parece mucho más rápido que el simple uso de un ciclo' for' para Python puro. La sobrecarga de usar enteros largos de Python parece devorar cualquier ganancia que se pueda obtener del bucle en C. Como se comentó en el hilo de bugtracker enlazado de Python, si realmente quieres rendimiento para este tipo de cosas, usa 'gmpy'. –

+0

@JohnY No estoy seguro de qué implementación elegir es importante, más allá del algoritmo elegido. Es imposible obtener un buen rendimiento con el algoritmo ingenuo, ya sea que lo codifique manualmente o lo escriba en un lenguaje de alto nivel. – agf

Cuestiones relacionadas