Python Language
Exposiciónción
Buscar..
Sintaxis
- valor1 ** valor2
- pow (valor1, valor2 [, valor3])
- value1 .__ pow __ (value2 [, value3])
- valor2 .__ rpow __ (valor1)
- operator.pow (valor1, valor2)
- operador .__ pow __ (valor1, valor2)
- math.pow (value1, value2)
- math.sqrt (valor1)
- math.exp (value1)
- cmath.exp (valor1)
- math.expm1 (value1)
Raíz cuadrada: math.sqrt () y cmath.sqrt
El módulo math
contiene la función math.sqrt()
que puede calcular la raíz cuadrada de cualquier número (que se puede convertir en un float
) y el resultado siempre será un float
:
import math
math.sqrt(9) # 3.0
math.sqrt(11.11) # 3.3331666624997918
math.sqrt(Decimal('6.25')) # 2.5
La función math.sqrt()
genera un ValueError
si el resultado sería complex
:
math.sqrt(-10)
ValueError: error de dominio matemático
math.sqrt(x)
es más rápido que math.pow(x, 0.5)
o x ** 0.5
pero la precisión de los resultados es la misma. El módulo cmath
es extremadamente similar al módulo math
, excepto por el hecho de que puede calcular números complejos y todos sus resultados tienen la forma de a + bi. También puede usar .sqrt()
:
import cmath
cmath.sqrt(4) # 2+0j
cmath.sqrt(-4) # 2j
¿Qué pasa con la j
? j
es el equivalente a la raíz cuadrada de -1. Todos los números se pueden poner en la forma a + bi, o en este caso, a + bj. a
es la parte real del número como el 2 en 2+0j
. Como no tiene una parte imaginaria, b
es 0. b
representa parte de la parte imaginaria del número como el 2 en 2j
. Como no hay una parte real en esto, 2j
también puede escribirse como 0 + 2j
.
Exposiciónción utilizando builtins: ** y pow ()
Exponenciación se puede utilizar mediante el uso de la orden interna pow
-Función o el **
operador:
2 ** 3 # 8
pow(2, 3) # 8
Para la mayoría de las operaciones aritméticas (todas en Python 2.x), el tipo de resultado será el del operando más amplio. Esto no es cierto para **
; Los siguientes casos son excepciones a esta regla:
Base:
int
, exponente:int < 0
:2 ** -3 # Out: 0.125 (result is a float)
Esto también es válido para Python 3.x.
Antes de Python 2.2.0, esto
ValueError
unValueError
.Base:
int < 0
ofloat < 0
, exponente:float != int
(-2) ** (0.5) # also (-2.) ** (0.5) # Out: (8.659560562354934e-17+1.4142135623730951j) (result is complex)
Antes de Python 3.0.0, esto
ValueError
unValueError
.
El módulo operator
contiene dos funciones que son equivalentes al operador **
:
import operator
operator.pow(4, 2) # 16
operator.__pow__(4, 3) # 64
o uno podría llamar directamente al método __pow__
:
val1, val2 = 4, 2
val1.__pow__(val2) # 16
val2.__rpow__(val1) # 16
# in-place power operation isn't supported by immutable classes like int, float, complex:
# val1.__ipow__(val2)
Exposiciónción utilizando el módulo matemático: math.pow ()
El módulo math
contiene otra función math.pow()
. La diferencia con el operador incorporado pow()
-function o **
es que el resultado es siempre un float
:
import math
math.pow(2, 2) # 4.0
math.pow(-2., 2) # 4.0
Lo que excluye los cálculos con entradas complejas:
math.pow(2, 2+0j)
TypeError: no se puede convertir complejo a flotar
y cálculos que conducirían a resultados complejos:
math.pow(-2, 0.5)
ValueError: error de dominio matemático
Función exponencial: math.exp () y cmath.exp ()
Tanto el módulo math
como el módulo cmath
contienen el número de Euler: e, y usarlo con la función pow()
incorporada o el operador **
funciona principalmente como math.exp()
:
import math
math.e ** 2 # 7.3890560989306495
math.exp(2) # 7.38905609893065
import cmath
cmath.e ** 2 # 7.3890560989306495
cmath.exp(2) # (7.38905609893065+0j)
Sin embargo, el resultado es diferente y usar la función exponencial directamente es más confiable que la exponenciación math.e
con base math.e
:
print(math.e ** 10) # 22026.465794806703
print(math.exp(10)) # 22026.465794806718
print(cmath.exp(10).real) # 22026.465794806718
# difference starts here ---------------^
Función exponencial menos 1: math.expm1 ()
El módulo math
contiene la función expm1()
que puede calcular la expresión math.e ** x - 1
para x
muy pequeña con mayor precisión que math.exp(x)
o cmath.exp(x)
permitiría:
import math
print(math.e ** 1e-3 - 1) # 0.0010005001667083846
print(math.exp(1e-3) - 1) # 0.0010005001667083846
print(math.expm1(1e-3)) # 0.0010005001667083417
# ------------------^
Para x muy pequeño la diferencia se hace más grande:
print(math.e ** 1e-15 - 1) # 1.1102230246251565e-15
print(math.exp(1e-15) - 1) # 1.1102230246251565e-15
print(math.expm1(1e-15)) # 1.0000000000000007e-15
# ^-------------------
La mejora es significativa en la computación científica. Por ejemplo, la ley de Planck contiene una función exponencial menos 1:
def planks_law(lambda_, T):
from scipy.constants import h, k, c # If no scipy installed hardcode these!
return 2 * h * c ** 2 / (lambda_ ** 5 * math.expm1(h * c / (lambda_ * k * T)))
def planks_law_naive(lambda_, T):
from scipy.constants import h, k, c # If no scipy installed hardcode these!
return 2 * h * c ** 2 / (lambda_ ** 5 * (math.e ** (h * c / (lambda_ * k * T)) - 1))
planks_law(100, 5000) # 4.139080074896474e-19
planks_law_naive(100, 5000) # 4.139080073488451e-19
# ^----------
planks_law(1000, 5000) # 4.139080128493406e-23
planks_law_naive(1000, 5000) # 4.139080233183142e-23
# ^------------
Métodos mágicos y exponenciales: incorporados, matemáticos y matemáticos.
Suponiendo que tienes una clase que almacena valores puramente enteros:
class Integer(object):
def __init__(self, value):
self.value = int(value) # Cast to an integer
def __repr__(self):
return '{cls}({val})'.format(cls=self.__class__.__name__,
val=self.value)
def __pow__(self, other, modulo=None):
if modulo is None:
print('Using __pow__')
return self.__class__(self.value ** other)
else:
print('Using __pow__ with modulo')
return self.__class__(pow(self.value, other, modulo))
def __float__(self):
print('Using __float__')
return float(self.value)
def __complex__(self):
print('Using __complex__')
return complex(self.value, 0)
Usando la función pow
incorporada o el operador **
siempre llama a __pow__
:
Integer(2) ** 2 # Integer(4)
# Prints: Using __pow__
Integer(2) ** 2.5 # Integer(5)
# Prints: Using __pow__
pow(Integer(2), 0.5) # Integer(1)
# Prints: Using __pow__
operator.pow(Integer(2), 3) # Integer(8)
# Prints: Using __pow__
operator.__pow__(Integer(3), 3) # Integer(27)
# Prints: Using __pow__
El segundo argumento del método __pow__()
solo se puede suministrar usando la función builtinpow pow()
o llamando directamente al método:
pow(Integer(2), 3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Integer(2).__pow__(3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Mientras que las funciones math
siempre lo convierten en un float
y usan el cálculo de flotación:
import math
math.pow(Integer(2), 0.5) # 1.4142135623730951
# Prints: Using __float__
cmath
funciones intentan convertirlo en complex
pero también pueden retroceder a float
si no hay una conversión explícita a complex
:
import cmath
cmath.exp(Integer(2)) # (7.38905609893065+0j)
# Prints: Using __complex__
del Integer.__complex__ # Deleting __complex__ method - instances cannot be cast to complex
cmath.exp(Integer(2)) # (7.38905609893065+0j)
# Prints: Using __float__
Ni math
ni cmath
funcionarán si también __float__()
el __float__()
:
del Integer.__float__ # Deleting __complex__ method
math.sqrt(Integer(2)) # also cmath.exp(Integer(2))
TypeError: se requiere un flotador
Exponenciación modular: pow () con 3 argumentos.
Al suministrar pow()
con 3 argumentos pow(a, b, c)
evalúa la exponenciación modular a b mod c :
pow(3, 4, 17) # 13
# equivalent unoptimized expression:
3 ** 4 % 17 # 13
# steps:
3 ** 4 # 81
81 % 17 # 13
Para los tipos incorporados, el uso de exponenciación modular solo es posible si:
- El primer argumento es un
int
- El segundo argumento es un
int >= 0
- El tercer argumento es un
int != 0
Estas restricciones también están presentes en Python 3.x
Por ejemplo, uno puede usar la forma de 3 argumentos de pow
para definir una función inversa modular :
def modular_inverse(x, p):
"""Find a such as a·x ≡ 1 (mod p), assuming p is prime."""
return pow(x, p-2, p)
[modular_inverse(x, 13) for x in range(1,13)]
# Out: [1, 7, 9, 10, 8, 11, 2, 5, 3, 4, 6, 12]
Raíces: raíz nth con exponentes fraccionarios
Si bien la función math.sqrt
se proporciona para el caso específico de raíces cuadradas, a menudo es conveniente usar el operador de exponenciación ( **
) con exponentes fraccionarios para realizar operaciones de raíz nth, como las raíces cúbicas.
La inversa de una exponenciación es la exponenciación por el recíproco del exponente. Entonces, si puedes calcular un número colocándolo en el exponente de 3, puedes encontrar la raíz cúbica de un número poniéndolo en el exponente de 1/3.
>>> x = 3
>>> y = x ** 3
>>> y
27
>>> z = y ** (1.0 / 3)
>>> z
3.0
>>> z == x
True
Cálculo de grandes raíces enteras
A pesar de que Python admite de forma nativa grandes enteros, tomar la raíz n de números muy grandes puede fallar en Python.
x = 2 ** 100
cube = x ** 3
root = cube ** (1.0 / 3)
OverflowError: largo int demasiado grande para convertirlo en flotante
Cuando trate con enteros tan grandes, necesitará usar una función personalizada para calcular la enésima raíz de un número.
def nth_root(x, n):
# Start with some reasonable bounds around the nth root.
upper_bound = 1
while upper_bound ** n <= x:
upper_bound *= 2
lower_bound = upper_bound // 2
# Keep searching for a better result as long as the bounds make sense.
while lower_bound < upper_bound:
mid = (lower_bound + upper_bound) // 2
mid_nth = mid ** n
if lower_bound < mid and mid_nth < x:
lower_bound = mid
elif upper_bound > mid and mid_nth > x:
upper_bound = mid
else:
# Found perfect nth root.
return mid
return mid + 1
x = 2 ** 100
cube = x ** 3
root = nth_root(cube, 3)
x == root
# True