duda de optimizacion

Francesc Alted faltet en pytables.org
Mar Abr 28 12:38:32 CEST 2009


A Tuesday 28 April 2009, Chema Cortes escrigué:
> El día 27 de abril de 2009 3:49, lasizoillo <lasizoillo en gmail.com> 
escribió:
> > El segundo es más rápido tambien. Definitivamente x**y parece que
> > mola más.
>
> Son operaciones distintas. math.pow utiliza la librería matemática de
> C, operando con reales en coma flotante; mientras que la segunda
> operación se implementa directamente por el lenguaje. Si la base es
> entera, la segunda operación debería la más eficiente; si son reales,
> en teoría debería ser más eficiente la primera (math.pow), aunque hay
> que precisar más...
>
> Al medir tiempos hay que tener en cuenta la sobrecarga que supone
> pasar los parámetros a la función:
>
>
> def f(n,p): return n**p
>
> timeit 2**100   -->  27.2 ns per loop
> timeit f(2,100)  --> 1.92 µs per loop
>
> timeit 2.0**100   -->  27.2 ns per loop
> timeit f(2.0,100) --> 323 ns per loop
>
>
> La sobrecarga del paso de parámetros hace que, paradójicamente, tarde
> más la operación con números enteros (largos) que con reales.

Pues sí que es curioso, yo también lo puedo reproducir :-\  Supongo que 
debe haber algún problema en algún sitio, pero no parece que el paso de 
parámetros sea el responsable.  Por ejemplo:

In [41]: def f2(n,p): return n*p
   ....:

In [42]: timeit f2(2,10)
10000000 loops, best of 3: 166 ns per loop

In [43]: timeit f2(2.,10)
1000000 loops, best of 3: 179 ns per loop

o sea, que más o menos se tarda lo mismo en pasar un entero que un 
número en coma flotante (como debe ser).  Puede que el problema sea más 
bien el método de medida, pero no lo tengo claro.

Más al hilo de la pregunta original, si se está interesado en efectuar 
operaciones matemáticas de manera veloz, lo mejor es siempre acudir a 
paquetes optimizados a tal efecto, como NumPy [1].  Un ejemplo:

In [44]: import numpy

In [45]: a = np.arange(1e6)

In [46]: timeit a**10
10 loops, best of 3: 141 ms per loop

Donde como se ve, se tarda unos 141 ms / 1e6 ~= 141 ns por elemento.  Se 
pueden obtener velocidades aún superiores con paquetes específicos como 
numexpr [2], que se han optimizado para determinados rangos de valores.  
Usando el ejemplo anterior:

In [47]: import numexpr

In [48]: timeit numexpr.evaluate("a**10")
100 loops, best of 3: 5.89 ms per loop

donde el tiempo queda reducido a unos 6 ns por elemento, lo cual es 
realmente rápido.

[1] http://numpy.scipy.org
[2] http://code.google.com/p/numexpr

Saludos,

-- 
Francesc Alted

"One would expect people to feel threatened by the 'giant
brains or machines that think'.  In fact, the frightening
computer becomes less frightening if it is used only to
simulate a familiar noncomputer."

-- Edsger W. Dykstra
   "On the cruelty of really teaching computer science"
_______________________________________________
Lista de correo Python-es 
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes





Más información sobre la lista de distribución Python-es