Python Language
Exponentiation
Recherche…
Syntaxe
- valeur1 ** valeur2
- pow (valeur1, valeur2 [, valeur3])
- valeur1 .__ pow __ (valeur2 [, valeur3])
- valeur2 .__ rpow __ (valeur1)
- operator.pow (value1, value2)
- opérateur .__ pow __ (valeur1, valeur2)
- math.pow (valeur1, valeur2)
- math.sqrt (value1)
- math.exp (valeur1)
- cmath.exp (value1)
- math.expm1 (valeur1)
Racine carrée: math.sqrt () et cmath.sqrt
Le module math
contient la fonction math.sqrt()
qui peut calculer la racine carrée de n'importe quel nombre (qui peut être converti en un float
) et le résultat sera toujours un float
:
import math
math.sqrt(9) # 3.0
math.sqrt(11.11) # 3.3331666624997918
math.sqrt(Decimal('6.25')) # 2.5
La fonction math.sqrt()
déclenche une ValueError
si le résultat est complex
:
math.sqrt(-10)
ValueError: erreur de domaine mathématique
math.sqrt(x)
est plus rapide que math.pow(x, 0.5)
ou x ** 0.5
mais la précision des résultats est la même. Le module cmath
est extrêmement similaire au module math
, sauf qu'il peut calculer des nombres complexes et que tous ses résultats sont sous la forme d'un + bi. Il peut aussi utiliser .sqrt()
:
import cmath
cmath.sqrt(4) # 2+0j
cmath.sqrt(-4) # 2j
C'est quoi le j
? j
est l'équivalent de la racine carrée de -1. Tous les nombres peuvent être mis sous la forme a + bi, ou dans ce cas, a + bj. a
est la partie réelle du nombre comme le 2 en 2+0j
. Comme il n'a pas de partie imaginaire, b
vaut 0. b
représente une partie de la partie imaginaire du nombre comme le 2 en 2j
. Comme il n'y a pas de véritable partie, 2j
peut aussi être écrit 0 + 2j
.
Exponentiation à l'aide des commandes intégrées: ** et pow ()
L'exponentiation peut être utilisée en utilisant la fonction pow
intégrée ou l'opérateur **
:
2 ** 3 # 8
pow(2, 3) # 8
Pour la plupart des opérations arithmétiques (toutes en Python 2.x), le type de résultat sera celui de l'opérande plus large. Ce n'est pas vrai pour **
; les cas suivants sont des exceptions à cette règle:
Base:
int
, exposant:int < 0
:2 ** -3 # Out: 0.125 (result is a float)
Ceci est également valable pour Python 3.x.
Avant Python 2.2.0, cela
ValueError
uneValueError
.Base:
int < 0
oufloat < 0
, exposant:float != int
(-2) ** (0.5) # also (-2.) ** (0.5) # Out: (8.659560562354934e-17+1.4142135623730951j) (result is complex)
Avant python 3.0.0, cela
ValueError
uneValueError
.
Le module d' operator
contient deux fonctions équivalentes à l'opérateur **
:
import operator
operator.pow(4, 2) # 16
operator.__pow__(4, 3) # 64
ou on pourrait appeler directement la méthode __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)
Exponentiation utilisant le module mathématique: math.pow ()
Le module math
contient une autre fonction math.pow()
. La différence avec la fonction intégrée pow()
ou **
est que le résultat est toujours un float
:
import math
math.pow(2, 2) # 4.0
math.pow(-2., 2) # 4.0
Ce qui exclut les calculs avec des entrées complexes:
math.pow(2, 2+0j)
TypeError: impossible de convertir un complexe en float
et des calculs qui conduiraient à des résultats complexes:
math.pow(-2, 0.5)
ValueError: erreur de domaine mathématique
Fonction exponentielle: math.exp () et cmath.exp ()
Les deux math
et cmath
-module contiennent le numéro d'Euler: e et son utilisation avec la fonction intégrée pow()
ou **
-operator fonctionne principalement comme 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)
Cependant, le résultat est différent et l'utilisation directe de la fonction exponentielle est plus fiable que l'exponentiation intégrée avec 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 ---------------^
Fonction exponentielle moins 1: math.expm1 ()
Le module math
contient la fonction expm1()
qui peut calculer l’expression math.e ** x - 1
pour de très petits x
avec une précision supérieure à math.exp(x)
de math.exp(x)
ou cmath.exp(x)
:
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
# ------------------^
Pour très petit x la différence est plus 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
# ^-------------------
L'amélioration est significative en informatique scientifique. Par exemple, la loi de Planck contient une fonction exponentielle moins 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éthodes magiques et exponentiation: intégré, math et cmath
En supposant que vous ayez une classe qui stocke des valeurs uniquement entières:
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)
L'utilisation de la fonction pow
intégrée ou de l'opérateur **
appelle toujours __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__
Le second argument de la __pow__()
ne peut être fourni que par l’utilisation de la méthode pow()
ou en appelant directement la méthode:
pow(Integer(2), 3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Integer(2).__pow__(3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Alors que les fonctions math
convertissent toujours en float
et utilisent le calcul flottant:
import math
math.pow(Integer(2), 0.5) # 1.4142135623730951
# Prints: Using __float__
cmath
cmath tentent de le convertir en complex
mais peuvent également basculer en mode float
s'il n'y a pas de conversion explicite en 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
ne fonctionneront si la __float__()
est également manquante:
del Integer.__float__ # Deleting __complex__ method
math.sqrt(Integer(2)) # also cmath.exp(Integer(2))
TypeError: un float est requis
Exponentiation modulaire: pow () avec 3 arguments
Fournir pow()
avec 3 arguments pow(a, b, c)
évalue l’ exponentiation modulaire a b mod c :
pow(3, 4, 17) # 13
# equivalent unoptimized expression:
3 ** 4 % 17 # 13
# steps:
3 ** 4 # 81
81 % 17 # 13
Pour les types intégrés utilisant une exponentiation modulaire n'est possible que si:
- Le premier argument est un
int
- Le second argument est un
int >= 0
- Le troisième argument est un
int != 0
Ces restrictions sont également présentes dans python 3.x
Par exemple, on peut utiliser la forme à trois arguments de pow
pour définir une fonction inverse modulaire :
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]
Racines: racine nième avec exposants fractionnaires
Bien que la fonction math.sqrt
soit fournie pour le cas spécifique des racines carrées, il est souvent pratique d'utiliser l'opérateur d'exponentiation ( **
) avec des exposants fractionnaires pour effectuer des opérations nth-root, comme les racines de cube.
L'inverse d'une exponentiation est une exponentiation par la réciproque de l'exposant. Donc, si vous pouvez cuber un nombre en le plaçant à l'exposant de 3, vous pouvez trouver la racine du cube d'un nombre en le mettant à l'exposant de 1/3.
>>> x = 3
>>> y = x ** 3
>>> y
27
>>> z = y ** (1.0 / 3)
>>> z
3.0
>>> z == x
True
Calculer de grandes racines entières
Même si Python prend en charge nativement les grands nombres entiers, prendre la nième racine de très grands nombres peut échouer en Python.
x = 2 ** 100
cube = x ** 3
root = cube ** (1.0 / 3)
OverflowError: long int trop grand pour être converti en float
Lorsque vous traitez de tels entiers, vous devrez utiliser une fonction personnalisée pour calculer la nième racine d'un nombre.
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