2014-11-06 14 views
7

Ho scelto questi numeri in modo casuale, ma questi risultati sembrano essere coerenti --- un esponente float è più veloce del 25% -50% rispetto a un intero. Come vengono gestiti diversamente?Perché numpy.power è più lento per gli esponenti interi?

In [209]: %timeit -n 100000 -r 100 np.power(3.71242, 7) 
100000 loops, best of 100: 3.45 µs per loop 

In [210]: %timeit -n 100000 -r 100 np.power(3.71242, 7.0) 
100000 loops, best of 100: 1.98 µs per loop 
+0

Se dovessi azzardare un'ipotesi, numpy si aspetta un float ma ha ricevuto un int e aveva bisogno di convertire. –

+0

@JeffMercado idea interessante --- ma non sembra proprio sommare: "% timeit -n 100000 -r 10 if (type (2) == int): float (2)" ==> "100000 loop, best of 10: 571 ns per loop " – DilithiumMatrix

+0

Sospetto che un esponente int sia causa di una moltiplicazione effettiva mentre un esponente float causa l'uso dei log. –

risposta

13

np.power è una universal function (ufunc). Queste funzioni possono essere utilizzate su scalari e array che hanno una varietà di tipi di dati diversi, ma devono prima verificare il tipo di valori di input in modo che possano determinare quale loop interno utilizzare per generare valori di output adatti.

Se i tipi di input non si associano a nessuno dei loop predefiniti di ufunc, l'ufunc proverà a cast the input values to suitable types (a meno che non venga indicato diversamente). Questo controllo e conversione dei valori di input ha un costo di prestazione ad esso associato, che spiega i tempi osservati nella domanda.

L'attributo types di un ufunc mostra come i tipi di dati di input verranno mappati su un tipo di dati di uscita. Di seguito è riportato l'elenco delle mappature per np.power:

>>> np.power.types # 'input input -> output' 
['bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L', 'qq->q', 
'QQ->Q', 'ee->e', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', 'GG->G', 'OO->O'] 

numeri a virgola mobile appartengono al codice di carattere 'g', interi Python appartengono 'l'. Un elenco completo di questi codici carattere può essere trovato here.

Si noti che per questo ufunc, i tipi di dati dei due valori di input devono essere uguali. Ad esempio, non esiste alcuna mappatura per un mix di tipi di dati di input float e int input.

Ma possiamo ancora dare np.power tipi di dati diversi e lasciarli trasmettere i valori ai tipi di dati appropriati. Per un float ed un int, un numero float64 viene restituito:

>>> np.power(3.71242, 7).dtype 
dtype('float64') 

sopra si può vedere che l'unico input che associa al codice float64 carattere g è di due altri g valori: 'gg->g'.

Così, dietro le quinte, ha preso un np.power(3.71242, 7) Python float e Python int e ha dovuto decidere quale potrebbe tranquillamente rifusione e di quale tipo. Il valore int è stato promosso in modo sicuro a un tipo float g. L'ufunc allora sapeva quale ciclo eseguire e restituiva un altro valore g.

Per questo motivo, il mancato mix dei tipi di dati di input offre prestazioni migliori per np.power.

Problemi correlati