2017-08-07 17 views
22

I np.power(a, b) sobie sprawę, że jest mniejsza niż np.exp(b * np.log(a)):Jakie dodatkowe prace wykonuje np.power?

import numpy as np 
a, b = np.random.random((2, 100000)) 
%timeit np.power(a, b) # best of 3: 4.16 ms per loop 
%timeit np.exp(b * np.log(a)) # best of 3: 1.74 ms per loop 

Wyniki są takie same (z niewielką ilością błędów numerycznych rzędu 1E-16).

Jakie dodatkowe prace wykonuje się w np.power? Ponadto, w jaki sposób mogę znaleźć odpowiedź na tego rodzaju pytania?

+6

Cały kod źródłowy jest dostępny na https://github.com/numpy/numpy, znalazłem tam kilka funkcji 'power' i nie mogę być pewien, który jest który (nie poświęcam czasu na jego przeglądanie), ale możesz tam spróbować, po prostu szukaj z cytatami "def power" jako start –

+0

@OferSadan Czy możesz mi powiedzieć trochę więcej, gdzie znalazłeś te funkcje 'mocy', nie możesz ich znaleźć sam (włącza się NumPy to naprawdę duże ...) –

+0

Na górze strony [github page] (https://github.com/numpy/numpy) znajduje się pole wyszukiwania. Wpisując '" def power "' znajduje 3 trafienia. – unutbu

Odpowiedz

32

Under the hood oba wyrażenia wywołać odpowiednie funkcje C pow lub exp i log i running a profiling on those in C++ bez kodu numpy daje:

pow  : 286 ms 
exp(log) : 93 ms 

Jest to zgodne z NumPy taktowania. Wydaje się więc, że główną różnicą jest to, że funkcja C pow jest wolniejsza niż exp(log).

Dlaczego? Wydaje się, że część rezonansu jest taka, że ​​wyrażenia nie są równoważne dla wszystkich danych wejściowych. Na przykład, przy ujemnym a i całkowitą b, power prace podczas exp(log) zawiedzie:

>>> np.power(-2, 2) 
4 
>>> np.exp(2 * np.log(-2)) 
nan 

Innym przykładem jest 0 ** 0:

>>> np.power(0, 0) 
1 
>>> np.exp(0 * np.log(0)) 
nan 

Stąd exp(log) sztuczka działa tylko w podgrupie wejść, natomiast power działa na wszystkich (ważnych) danych wejściowych.

Oprócz tego, power gwarantuje pełną precyzję zgodnie z IEEE 754 standard, podczas gdy exp(log) może cierpieć z powodu błędów zaokrąglania.

+2

A co do pytania OP dotyczącego samodzielnego znalezienia odpowiedzi - sprawdziłem debuggera pod kątem typu: 'np.power',' np.log', 'np.exp' - było to' ufunc' oraz w dokumentacji numpy znalazłem, że są one zdefiniowane w 'generate_umath.py' jako:' pow', 'log' i' npy_ObjectPower'. Ostatnia z nich to funkcja C znaleziona w [tym pliku] (https://raw.githubusercontent.com/numpy/numpy/d46df62746995481439b650790589e60a8070172/numpy/core/src/umath/funcs.inc.src) i zwraca 'PyNumber_Power' oraz jest to w rzeczywistości Python 'pow' [zgodnie z dokumentami] (https://docs.python.org/3/c-api/number.html) – pierscin

+3

Ponadto' pow() 'zawsze daje pełną dokładność podwójnej precyzji liczby zmiennoprzecinkowe, nawet w przypadkach, gdy kombinacja 'exp()' i 'log()' traci kilka cyfr. –

+0

Możesz rzeczywiście zrobić "log lew" z negatywami, jeśli przypiszesz 'a = a.astype (complex) 'i wyciągnij prawdziwą część, ale tracisz przewagę prędkości –