2010-07-11 14 views
5

consideri il seguente codice (da here, con il numero di test aumentato):Perché Python 3.1 è più lento di 2.6 per questo codice?

from timeit import Timer 

def find_invpow(x,n): 
    """Finds the integer component of the n'th root of x, 
    an integer such that y ** n <= x < (y + 1) ** n. 
    """ 
    high = 1 
    while high ** n < x: 
     high *= 2 
    low = high/2 
    while low < high: 
     mid = (low + high) // 2 
     if low < mid and mid**n < x: 
      low = mid 
     elif high > mid and mid**n > x: 
      high = mid 
     else: 
      return mid 
    return mid + 1 

def find_invpowAlt(x,n): 
    """Finds the integer component of the n'th root of x, 
    an integer such that y ** n <= x < (y + 1) ** n. 
    """ 
    low = 10 ** (len(str(x))/n) 
    high = low * 10 
    while low < high: 
     mid = (low + high) // 2 
     if low < mid and mid**n < x: 
      low = mid 
     elif high > mid and mid**n > x: 
      high = mid 
     else: 
      return mid 
    return mid + 1 

x = 237734537465873465 
n = 5 
tests = 1000000 

print "Norm", Timer('find_invpow(x,n)', 'from __main__ import find_invpow, x,n').timeit(number=tests) 
print "Alt", Timer('find_invpowAlt(x,n)', 'from __main__ import find_invpowAlt, x,n').timeit(number=tests) 

Usare Python 2.6 (Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) [GCC 4.4.3] on linux2), i tempi riportati sono:

Norm 9.869 
Alt 9.53973197937 

Tuttavia, sulla stessa macchina utilizzando Python 3.1 (Python 3.1.2 (r312:79147, Apr 15 2010, 15:35:48) [GCC 4.4.3] on linux2), i tempi sono:

Norm 28.4206559658 
Alt 26.8007400036 

qualcuno sa perché questo cod e gira tre volte più lentamente su Python 3.1?

+1

no Repro: python3.1 è più veloce di 2.6 di circa il 30% sulla mia macchina. – SilentGhost

+0

Grazie. Quale sistema operativo stai utilizzando? Ottengo i tempi di cui sopra su Ubuntu 10.04 64-bit. – user200783

+0

Versione a 32 bit dello stesso sistema – SilentGhost

risposta

3

Ho ottenuto tempi costantemente decrescenti da 2,5, 2,6, 2,7 e 3,1 (Windows XP SP2) ... con la versione "/". Con //, le 3.1 volte erano drasticamente più piccole delle 2.X volte, ad es. "Norm" è scesa da 6.35 (py2.7) a 3.62 (py3.1).

Si noti che in 2.x, ci sono ints (parola macchina, 32 o 64 bit) e long (lunghezza variabile). In 3.x, long è stato rinominato int e int è andato via. La mia ipotesi è che la conversione da long a float potrebbe causare il tempo extra con /.

In ogni caso, una versione molto migliore "Alt" sarebbe iniziare con questo codice:

high = 1 
highpown = 1 
while highpown < x: 
    high <<= 1 
    highpown <<= n 
+0

"inizia con questo codice' ... '". Seguito da 'low = high // 2'? – user200783

+0

@Paul Baker: certo. 'low = high/2' è un BUG in ENTRAMBI le funzioni. –

+1

+1. Sospetto fortemente che sia l'aspetto 'int' versus' long' che fa la differenza. Si noti che su una macchina a 32 bit, i valori testati non si adattano a un int, quindi si farebbero calcoli con valori long in entrambi i file Python 2.xe 3.x. Ma su una macchina a 64 bit, stai usando l'aritmetica di 'int' in 2.x e l'aritmetica di precisione arbitraria in 3.x. –

2

L'operatore // esegue la divisione intera (o divisione floor) in entrambi python 2 e 3, mentre l'operatore / esegue la divisione floor in python 2 con gli operandi interi e la vera divisione in python 3 dato qualsiasi operando.

Provare a sostituire l'operatore / con l'operatore //.

+0

Grazie. Ho sostituito 'low = high/2' con' low = high // 2' e 'low = 10 ** (len (str (x))/n)' con 'low = 10 ** (len (str (x)) // n) '. Ciò ha portato le prestazioni di 2.6 con 'from __future__ import division 'in linea con le regolari prestazioni di 2.6. Sfortunatamente la performance di 3.1 è rimasta invariata - ancora 3 volte più lenta di 2.6. – user200783

+0

Ovviamente, il problema è che gli "interi" in python3 sono i vecchi "long" di python2. L'operatore non importa qui :) –

Problemi correlati