Python Language
elevamento a potenza
Ricerca…
Sintassi
- valore1 ** valore2
- pow (valore1, valore2 [, valore3])
- valore1 .__ pow __ (valore2 [, valore3])
- valore2 .__ rpow __ (valore1)
- operator.pow (valore1, valore2)
- operatore .__ pow __ (valore1, valore2)
- math.pow (valore1, valore2)
- Math.sqrt (valore1)
- math.exp (valore1)
- cmath.exp (valore1)
- math.expm1 (valore1)
Radice quadrata: math.sqrt () e cmath.sqrt
Il modulo math
contiene la funzione math.sqrt()
che può calcolare la radice quadrata di qualsiasi numero (che può essere convertito in un float
) e il risultato sarà sempre un float
:
import math
math.sqrt(9) # 3.0
math.sqrt(11.11) # 3.3331666624997918
math.sqrt(Decimal('6.25')) # 2.5
La funzione math.sqrt()
solleva math.sqrt()
ValueError
se il risultato sarebbe complex
:
math.sqrt(-10)
ValueError: errore del dominio matematico
math.sqrt(x)
è più veloce di math.pow(x, 0.5)
o x ** 0.5
ma la precisione dei risultati è la stessa. Il modulo cmath
è estremamente simile al modulo math
, tranne per il fatto che può calcolare numeri complessi e tutti i suoi risultati sono nella forma di un + bi. Può anche usare .sqrt()
:
import cmath
cmath.sqrt(4) # 2+0j
cmath.sqrt(-4) # 2j
Cosa c'è nella j
? j
è l'equivalente della radice quadrata di -1. Tutti i numeri possono essere messi in forma a + bi, o in questo caso, a + bj. a
è la parte reale del numero come il 2 in 2+0j
. Poiché non ha una parte immaginaria, b
è 0. b
rappresenta parte della parte immaginaria del numero come il 2 in 2j
. Poiché non c'è una parte reale in questo, 2j
può anche essere scritto come 0 + 2j
.
Esponenziazione usando i builtin: ** e pow ()
L'esponenziazione può essere utilizzata utilizzando la funzione integrata pow
o l'operatore **
:
2 ** 3 # 8
pow(2, 3) # 8
Per la maggior parte delle operazioni aritmetiche (tutte in Python 2.x) il tipo di risultato sarà quello dell'operando più ampio. Questo non è vero per **
; i seguenti casi sono eccezioni a questa regola:
Base:
int
, esponente:int < 0
:2 ** -3 # Out: 0.125 (result is a float)
Questo è valido anche per Python 3.x.
Prima di Python 2.2.0, questo ha generato un
ValueError
.Base:
int < 0
ofloat < 0
, esponente:float != int
(-2) ** (0.5) # also (-2.) ** (0.5) # Out: (8.659560562354934e-17+1.4142135623730951j) (result is complex)
Prima di python 3.0.0, questo ha generato un
ValueError
.
Il modulo operator
contiene due funzioni equivalenti al **
-operator:
import operator
operator.pow(4, 2) # 16
operator.__pow__(4, 3) # 64
oppure si potrebbe chiamare direttamente il metodo __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)
Esponenziazione usando il modulo matematico: math.pow ()
Il modulo math
contiene un'altra funzione math.pow()
. La differenza con la funzione built-in pow()
o **
è che il risultato è sempre un float
:
import math
math.pow(2, 2) # 4.0
math.pow(-2., 2) # 4.0
Che esclude i calcoli con input complessi:
math.pow(2, 2+0j)
TypeError: impossibile convertire il complesso in float
e calcoli che porterebbero a risultati complessi:
math.pow(-2, 0.5)
ValueError: errore del dominio matematico
Funzione esponenziale: math.exp () e cmath.exp ()
Sia il modulo math
che il modulo cmath
contengono il numero di Eulero: e e lo utilizza con la funzione built-in pow()
o **
-operator funziona principalmente come 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)
Tuttavia, il risultato è diverso e l'utilizzo della funzione esponenziale direttamente è più affidabile rispetto alla funzione di esponenziazione integrata 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 ---------------^
Funzione esponenziale meno 1: math.expm1 ()
Il modulo math
contiene la funzione expm1()
che può calcolare l'espressione math.e ** x - 1
per x
molto piccolo con maggiore precisione rispetto a math.exp(x)
o cmath.exp(x)
consentirebbe:
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
# ------------------^
Per piccolissime x la differenza aumenta:
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
# ^-------------------
Il miglioramento è significativo nel calcolo scientifico. Ad esempio la legge di Planck contiene una funzione esponenziale meno 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
# ^------------
Metodi magici ed esponenziazione: builtin, matematica e cmath
Supponendo che tu abbia una classe che memorizza valori puramente interi:
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 funzione built-in pow
o **
operatore chiama sempre __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__
Il secondo argomento del metodo __pow__()
può essere fornito solo usando builtin- pow()
o chiamando direttamente il metodo:
pow(Integer(2), 3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Integer(2).__pow__(3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Mentre le funzioni math
lo convertono sempre in float
e usano il calcolo a virgola mobile:
import math
math.pow(Integer(2), 0.5) # 1.4142135623730951
# Prints: Using __float__
cmath
provano a convertirlo in un insieme complex
ma possono anche eseguire il fallback in modo che float
se non vi è alcuna conversione esplicita 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__
Né math
né cmath
funzioneranno se __float__()
anche il __float__()
:
del Integer.__float__ # Deleting __complex__ method
math.sqrt(Integer(2)) # also cmath.exp(Integer(2))
TypeError: è richiesto un float
Esponenziazione modulare: pow () con 3 argomenti
Fornire pow()
con 3 argomenti pow(a, b, c)
valuta l' esponenziazione modulare a b mod c :
pow(3, 4, 17) # 13
# equivalent unoptimized expression:
3 ** 4 % 17 # 13
# steps:
3 ** 4 # 81
81 % 17 # 13
Per i tipi built-in che utilizzano l'esponenziazione modulare è possibile solo se:
- Il primo argomento è un
int
- Il secondo argomento è un
int >= 0
- Il terzo argomento è un
int != 0
Queste restrizioni sono presenti anche in python 3.x
Ad esempio si può usare la forma a 3 argomenti di pow
per definire una funzione inversa modulare :
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]
Radici: nth-root con esponenti frazionali
Mentre la funzione math.sqrt
è fornita per il caso specifico di radici quadrate, è spesso conveniente usare l'operatore di math.sqrt
( **
) con esponenti frazionari per eseguire operazioni di nth-root, come le radici di cubi.
L'inverso di un esponenziazione è esponenziale dal reciproco dell'esponente. Quindi, se puoi cubare un numero mettendolo all'esponente di 3, puoi trovare la radice cubica di un numero mettendolo all'esponente di 1/3.
>>> x = 3
>>> y = x ** 3
>>> y
27
>>> z = y ** (1.0 / 3)
>>> z
3.0
>>> z == x
True
Calcolo di radici intere di grandi dimensioni
Anche se Python supporta in modo nativo i grandi numeri interi, l'uso dell'ennesima radice di numeri molto grandi può fallire in Python.
x = 2 ** 100
cube = x ** 3
root = cube ** (1.0 / 3)
OverflowError: long int troppo grande per essere convertito in float
Quando si ha a che fare con numeri interi così grandi, è necessario utilizzare una funzione personalizzata per calcolare l'ennesima radice di un numero.
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