Solución:
Usando el operador de energía **
será más rápido ya que no tendrá la sobrecarga de una llamada de función. Puede ver esto si desmonta 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 realmente en tiempo de compilación.
Ahora bien, en la práctica, esta diferencia no importa tanto, como puede ver al cronometrarla:
>>> 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
Entonces, mientras pow
y math.pow
son aproximadamente el doble de lentos, pero aún así son lo suficientemente rápidos como para no importarles mucho. A menos que pueda identificar la exponenciación como un cuello de botella, no habrá razón para elegir un método sobre el otro si la claridad disminuye. Esto se aplica especialmente desde pow
ofrece una operación de módulo integrada, por ejemplo.
Alfe hizo una buena pregunta en los comentarios anteriores:
timeit
muestra quemath.pow
es más lento que**
en todos los casos. Que esmath.pow()
bueno de todos modos? ¿Alguien tiene una idea de dónde puede ser de alguna ventaja entonces?
La gran diferencia de math.pow
tanto para el incorporado pow
y el operador de energía **
es asi siempre utiliza semántica flotante. Entonces, si, por alguna razón, desea asegurarse de obtener un flotador como resultado, entonces math.pow
asegurará esta propiedad.
Pensemos en un ejemplo: tenemos dos números, i
y j
y no tengo idea de si son números enteros o flotantes. Pero queremos tener un resultado flotante de i^j
. Entonces, ¿qué opciones tenemos?
- Podemos convertir al menos uno de los argumentos a un flotante y luego hacer
i ** j
. - Podemos hacer
i ** j
y convertir el resultado en un flotador (la exponencia del flotador se usa automáticamente cuandoi
oj
son flotantes, por lo que el resultado es el mismo). - Nosotros podemos usar
math.pow
.
Entonces, probemos esto:
>>> 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 se puede ver, math.pow
es en realidad más rápido! Y si lo piensa, 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, podría valer la pena señalar que el comportamiento de **
y pow
se puede anular mediante la implementación de la especial __pow__
(y __rpow__
) método para tipos personalizados. Entonces, si no quieres eso (por el motivo que sea), usa math.pow
no haré eso.
La función pow () le permitirá agregar un tercer argumento como módulo.
Por ejemplo: recientemente me enfrenté a un error de memoria al hacer
2 ** 23375247598357347582% 23375247598357347583
En cambio lo hice:
pow(2, 23375247598357347582, 23375247598357347583)
Esto regresa en meros milisegundos en lugar de la enorme cantidad de tiempo y memoria que toma el exponente simple. Entonces, cuando se trata de números grandes y módulo paralelo, pow () es más eficiente, sin embargo, cuando se trata de números más pequeños sin módulo, ** es más eficiente.
Solo por el protocolo: El **
el operador llama al incorporado pow
función que acepta un tercer argumento opcional (módulo) si los dos primeros argumentos son tipos enteros.
Entonces, si tiene la intención de calcular los residuos de las potencias, use la función incorporada. los math.pow
puede darle resultados falsos:
import math
base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)
Cuando ejecuté esto, obtuve 0.0
en el primer caso, lo que obviamente no puede ser cierto, porque 13 es impar (y por lo tanto todos sus poderes integrales). los math.pow
La versión utiliza una precisión limitada que provoca un error.
En aras de la justicia, debemos decir: math.pow
puede ser mucho más rápido:
import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("pow(2, 100)")
Esto es lo que obtengo como salida:
0.240936803195
1.4775809183
Algunos ejemplos en línea
- http://ideone.com/qaDWRd (resto incorrecto con
math.pow
) - http://ideone.com/g7J9Un (menor rendimiento con
pow
en valores int) - http://ideone.com/KnEtXj (rendimiento ligeramente inferior con
pow
en valores flotantes)