define - Exponenciales en python x.** y vs math.pow(x, y)
python cosine function (4)
Bueno, son para diferentes tareas, realmente.
Use pow
(equivalente a x ** y
con dos argumentos) cuando quiera una aritmética entera.
Y use math.pow
si cualquiera de los argumentos es flotante, y quiere salida flotante.
Para una discusión sobre las diferencias entre pow
y math.pow
, vea esta question .
¿Cuál es más eficiente usando math.pow o the ** operator? ¿Cuándo debería usar uno sobre el otro?
Hasta ahora sé que x**y
puede devolver un int
o un float
si usa un decimal la función pow
devolverá un float
import math
print math.pow(10, 2)
print 10. ** 2
Solo para el protocolo: el operador **
llama a la función pow
incorporada que acepta un tercer argumento opcional (módulo) si los primeros dos argumentos son tipos enteros.
Entonces, si tiene la intención de calcular los restos de las potencias, use 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 ejecuté 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). La versión math.pow
usa una precisión limitada que causa un error.
En aras de la equidad, debemos decir que 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 los valores int) - http://ideone.com/KnEtXj (rendimiento ligeramente inferior con
pow
en valores de flotación)
Usar el operador de energía **
será más rápido ya que no tendrá la sobrecarga de una llamada a función. Puedes ver esto si desarmas el código de 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 las expresiones constantes como 7. ** 5
realidad se evalúan en tiempo de compilación.
Ahora, en la práctica, esta diferencia no importa demasiado, como se puede ver cuando se mide el tiempo:
>>> 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 casi el doble de lentos, todavía son lo suficientemente rápidos para que no les importe demasiado. A menos que 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 ya que pow
ofrece una operación de módulo integrada, por ejemplo.
Alfe hizo una buena pregunta en los comentarios de arriba:
timeit
muestra quemath.pow
es más lento que**
en todos los casos. ¿math.pow()
qué sirvemath.pow()
? ¿Alguien tiene una idea de dónde puede ser de alguna ventaja?
La gran diferencia de math.pow
tanto para el pow
incorporado como para el power operator **
es que siempre usa la semántica de float. Por lo tanto, si usted, por alguna razón, quiere asegurarse de obtener una flotación como resultado, entonces math.pow
asegurará esta propiedad.
Pensemos en un ejemplo: tenemos dos números, i
y j
, y no tenemos idea de si son flotantes o enteros. Pero queremos tener un resultado flotante de i^j
. Entonces, ¿qué opciones tenemos?
- Podemos convertir al menos uno de los argumentos en un flotante y luego hacemos
i ** j
. - Podemos hacer
i ** j
y convertir el resultado en un flotante (la exponenciación flotante se usa automáticamente cuandoi
oj
son flotantes, por lo que el resultado es el mismo). - 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 puede ver, ¡ math.pow
es realmente más rápido! Y si lo piensas bien, la sobrecarga de la llamada a función también se ha ido ahora, porque en todas las otras alternativas tenemos que llamar a float()
.
Además, podría valer la pena señalar que el comportamiento de **
y pow
puede __pow__
implementando el __pow__
especial __pow__
(y __rpow__
) para tipos personalizados. Entonces, si no quieres eso (por alguna razón), usar math.pow
no hará eso.
**
es de hecho más rápido que 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 entonces
10.**2
La diferencia no es grande y no es notorio con una operación (usando timeit
), pero con una gran cantidad de operaciones puede ser significativa.