Exponenciales en python x. * * y vs math.pow (x, y)


Cuál es más eficiente usando matemáticas.pow o el operador**? ¿Cuándo debo usar uno sobre el otro?

Hasta ahora sé que x**y puede devolver un int o float si se utiliza un decimal la función pow devolverá un flotador

import math

print math.pow(10, 2)

print 10. ** 2
Author: Wolf, 2014-01-07

4 answers

Usar el power operator ** será más rápido ya que no tendrá la sobrecarga de una llamada a una función. Puedes ver esto si desensamblas el código Python:

>>> dis.dis('7. ** i')
  1           0 LOAD_CONST               0 (7.0) 
              3 LOAD_NAME                0 (i) 
              6 BINARY_POWER         
              7 RETURN_VALUE         
>>> dis.dis('pow(7., i)')
  1           0 LOAD_NAME                0 (pow) 
              3 LOAD_CONST               0 (7.0) 
              6 LOAD_NAME                1 (i) 
              9 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             12 RETURN_VALUE         
>>> dis.dis('math.pow(7, i)')
  1           0 LOAD_NAME                0 (math) 
              3 LOAD_ATTR                1 (pow) 
              6 LOAD_CONST               0 (7) 
              9 LOAD_NAME                2 (i) 
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             15 RETURN_VALUE         

Tenga en cuenta que estoy usando una variable i como exponente aquí porque expresiones constantes como 7. ** 5 se evalúan en tiempo de compilación.

Ahora, en la práctica, esta diferencia no importa mucho, como se puede ver cuando el tiempo es:

>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255

Así, mientras que pow y math.pow son aproximadamente el doble de lentos, aún son lo suficientemente rápidos como para no importarles mucho. A menos que realmente pueda identificar la exponenciación como un cuello de botella, no habrá una razón para elegir un método sobre el otro si la claridad disminuye. Esto se aplica especialmente desde pow ofrece una operación modulo integrada por ejemplo.


Alfe hizo una buena pregunta en los comentarios anteriores:

timeit muestra que math.pow es más lento que ** en todos los casos. ¿Para qué sirve math.pow()? ¿Alguien tiene una idea de dónde ¿puede ser de alguna ventaja entonces?

La gran diferencia de math.pow tanto para el builtin pow como para el power operator ** es que siempre utiliza la semántica de flotación. Así que si, por alguna razón, desea asegurarse de obtener un flotador como resultado de nuevo, entonces math.pow se asegurará de esta propiedad.

Pensemos en un ejemplo: Tenemos dos números, i y j, y no tenemos idea si son flotadores o enteros. Pero queremos tener un resultado flotante de i^j. Entonces, ¿qué opciones hacen ¿tenemos?

  • Podemos convertir al menos uno de los argumentos a un float y luego hacer i ** j.
  • Podemos hacer i ** j y convertir el resultado en un flotador (la exponencia flotante se usa automáticamente cuando i o j son flotadores, por lo que el resultado es el mismo).
  • Podemos usar math.pow.

Entonces, probemos esto: {[33]]}

>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439

Como puedes ver, math.pow es en realidad más rápido! Y si lo piensas, la sobrecarga de la llamada a la función también se ha ido ahora, porque en todas las otras alternativas tenemos que llamar float().


Además, vale la pena señalar que el comportamiento de ** y pow se puede anular implementando el método especial __pow__ (y __rpow__) para tipos personalizados. Así que si no quieres eso (por la razón que sea), usar math.pow no hará eso.

 64
Author: poke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-07 11:25:02

Solo para el protocolo: El operador ** llama a la función incorporada pow que acepta un tercer argumento opcional (módulo) si los dos primeros argumentos son tipos enteros.

Por lo tanto, si tiene la intención de calcular los restos de potencias, utilice la función incorporada. El math.pow puede darte resultados falsos:

import math

base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)

Cuando corrí esto, obtuve 0.0 en el primer caso que obviamente no puede ser cierto, porque 13 es impar (y por lo tanto todos sus poderes integrales). El math.pow la versión utiliza una precisión limitada que causa un error.

En aras de la justicia, debemos decir, math.pow puede ser mucho más rápido: {[15]]}

import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("pow(2, 100)")

Esto es lo que estoy obteniendo como salida:

0.240936803195
1.4775809183

Algunos ejemplos en línea

 4
Author: Wolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-14 06:58:45

Bueno, son para diferentes tareas, en realidad.

Use pow (equivalente a x ** y con dos argumentos) cuando desee aritmética de enteros.

Y use math.pow si cualquiera de los argumentos es float, y desea una salida float.

Para una discusión sobre las diferencias entre pow y math.pow, vea esta pregunta .

 3
Author: wim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:31:59

** es de hecho más rápido entonces math.pow(), pero si desea una función cuadrática simple como en su ejemplo, es aún más rápido usar un producto.

10.*10.

Será más rápido que

10.**2

La diferencia no es grande ni notoria con una operación (usando timeit), pero con un gran número de operaciones puede ser significativa.

 2
Author: KDhoore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-11 10:26:19