2012-03-22 14 views
31

ottengo i seguenti risultati sulla mia macchina:Perché math.factorial è molto più lento in Python 2.x rispetto a 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 
>>> 

Ho pensato che questo potrebbe avere qualcosa a che fare con lunghi conversione int /, ma factorial(10000L) non è più veloce a 2.7.

+0

10.000! - ti rendi conto di quanto sia grande quel numero? http://gimbo.org.uk/texts/ten_thousand_factorial.txt – duffymo

+7

@duffymo Questo non spiega la differenza di velocità –

+0

Non sto cercando di spiegarlo. Mi sto solo chiedendo se l'OP è a conoscenza, tutto qui. la conversione int/long non sembra rilevante. Dov'è la tua risposta, isbadawi? – duffymo

risposta

43

Python 2 utilizza il 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 utilizza il 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. 

Vedere la Python Bugtracker issue per la discussione. Grazie DSM per averlo indicato.

+11

Vedi http://bugs.python.org/issue8692 per la discussione. – DSM

+0

È interessante notare che, nonostante sia apparentemente implementato in C, 'math.factorial' in Python 2.x non sembra molto più veloce di un semplice ciclo' for' in puro Python. Il sovraccarico dell'uso di Python long interi sembra assorbire qualsiasi guadagno si possa ottenere dal loop in C. Come è stato commentato nel thread bugtracker collegato a Python, se si vuole veramente ottenere prestazioni per questo tipo di cose, usare 'gmpy'. –

+0

@JohnY Non sono sicuro che l'implementazione scelta sia importante, oltre all'algoritmo scelto. È impossibile ottenere buone prestazioni con l'algoritmo ingenuo, sia che lo si codifichi manualmente in assembly o lo si scriva in un linguaggio di alto livello. – agf

Problemi correlati