Python Language
exponentiering
Sök…
Syntax
- värde1 ** värde2
- pow (värde1, värde2 [, värde3])
- värde1 .__ pow __ (värde2 [, värde3])
- värde2 .__ rpow __ (värde1)
- operator.pow (värde1, värde2)
- operatör .__ pow __ (värde1, värde2)
- math.pow (värde1, värde2)
- math.sqrt (värde1)
- math.exp (värde1)
- cmath.exp (värde1)
- math.expm1 (värde1)
Fyrkantig rot: matematik.sqrt () och cmath.sqrt
math
innehåller math.sqrt()
-funktionen som kan beräkna kvadratroten av valfritt nummer (som kan konverteras till en float
) och resultatet kommer alltid att vara en float
:
import math
math.sqrt(9) # 3.0
math.sqrt(11.11) # 3.3331666624997918
math.sqrt(Decimal('6.25')) # 2.5
math.sqrt()
höjer en ValueError
om resultatet skulle vara complex
:
math.sqrt(-10)
ValueError: fel i matematisk domän
math.sqrt(x)
är snabbare än math.pow(x, 0.5)
eller x ** 0.5
men resultatens precision är densamma. cmath
modulen är mycket lik math
, förutom att den kan beräkna komplexa siffror och alla resultat är i form av en + bi. Den kan också använda .sqrt()
:
import cmath
cmath.sqrt(4) # 2+0j
cmath.sqrt(-4) # 2j
Vad är det med j
? j
motsvarar kvadratroten -1. Alla siffror kan placeras i formen a + bi, eller i detta fall, en + bj. a
är den verkliga delen av antalet som 2 i 2+0j
. Eftersom den inte har någon imaginär del, är b
0. b
representerar en del av den imaginära delen av antalet som 2 i 2j
. Eftersom det inte finns någon riktig del i detta kan 2j
också skrivas som 0 + 2j
.
Exponentiering med inbyggda: ** och pow ()
Exponentiering kan användas med hjälp av den inbyggda pow
funktionen eller **
-operatören:
2 ** 3 # 8
pow(2, 3) # 8
För de flesta (alla i Python 2.x) aritmetiska operationer blir resultatet typ av den bredare operanden. Detta är inte sant för **
; Följande fall är undantag från denna regel:
Bas:
int
, exponent:int < 0
:2 ** -3 # Out: 0.125 (result is a float)
Detta gäller också för Python 3.x.
Innan Python 2.2.0 höjde detta en
ValueError
.Bas:
int < 0
ellerfloat < 0
, exponent:float != int
(-2) ** (0.5) # also (-2.) ** (0.5) # Out: (8.659560562354934e-17+1.4142135623730951j) (result is complex)
Innan python 3.0.0 höjde detta en
ValueError
.
operator
innehåller två funktioner som motsvarar **
-operatören:
import operator
operator.pow(4, 2) # 16
operator.__pow__(4, 3) # 64
eller man kan direkt ringa __pow__
metoden:
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)
Exponentiering med matematikmodulen: math.pow ()
Den math
-modul innehåller en annan math.pow()
funktion. Skillnaden med den inbyggda pow()
-funktionen eller **
-operatören är att resultatet alltid är en float
:
import math
math.pow(2, 2) # 4.0
math.pow(-2., 2) # 4.0
Som utesluter beräkningar med komplexa ingångar:
math.pow(2, 2+0j)
TypeError: kan inte konvertera komplex till float
och beräkningar som skulle leda till komplexa resultat:
math.pow(-2, 0.5)
ValueError: fel i matematisk domän
Exponentiell funktion: math.exp () och cmath.exp ()
Både math
och cmath
modulen innehåller Euler-numret: e och att använda det med den inbyggda pow()
-funktionen eller **
-operatör fungerar mestadels som 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)
Resultatet är emellertid annorlunda och att använda exponentiell funktion direkt är mer pålitlig än inbyggd exponentiering med math.e
:
print(math.e ** 10) # 22026.465794806703
print(math.exp(10)) # 22026.465794806718
print(cmath.exp(10).real) # 22026.465794806718
# difference starts here ---------------^
Exponentiell funktion minus 1: math.expm1 ()
math
innehåller expm1()
-funktionen som kan beräkna uttrycket math.e ** x - 1
för mycket små x
med högre precision än math.exp(x)
eller cmath.exp(x)
skulle tillåta:
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
# ------------------^
För mycket små x blir skillnaden större:
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
# ^-------------------
Förbättringen är betydande i vetenskaplig datoranvändning. Till exempel innehåller Plancks lag en exponentiell funktion minus 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
# ^------------
Magiska metoder och exponentiering: inbyggd, matematik och cmath
Antar att du har en klass som lagrar rent heltal:
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)
Använda den inbyggda pow
funktionen eller **
__pow__
ringer alltid __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__
Det andra argumentet för __pow__()
kan endast tillhandahållas genom att använda det inbyggda pow()
eller genom att direkt anropa metoden:
pow(Integer(2), 3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Integer(2).__pow__(3, 4) # Integer(0)
# Prints: Using __pow__ with modulo
Medan math
alltid konverterar den till en float
och använder floatberäkningen:
import math
math.pow(Integer(2), 0.5) # 1.4142135623730951
# Prints: Using __float__
cmath
funktioner försöker konvertera det till complex
men kan också falla tillbaka till att float
om det inte finns någon uttrycklig konvertering till 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__
Varken math
eller cmath
fungerar om också __float__()
-metoden saknas:
del Integer.__float__ # Deleting __complex__ method
math.sqrt(Integer(2)) # also cmath.exp(Integer(2))
TypeError: en flottör krävs
Modular exponentiation: pow () med 3 argument
Att tillhandahålla pow()
med 3 argument pow(a, b, c)
utvärderar den modulära exponentieringen a b mod c :
pow(3, 4, 17) # 13
# equivalent unoptimized expression:
3 ** 4 % 17 # 13
# steps:
3 ** 4 # 81
81 % 17 # 13
För inbyggda typer som använder modulär exponentiering är det bara möjligt om:
- Det första argumentet är ett
int
- Det andra argumentet är ett
int >= 0
- Tredje argumentet är ett
int != 0
Dessa begränsningar finns också i python 3.x
Till exempel kan man använda 3-argumentformen för pow
att definiera en modulär invers funktion:
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]
Rötter: nth-rot med fraktionella exponenter
Medan math.sqrt
funktionen tillhandahålls för det specifika fallet med fyrkantiga rötter, är det ofta bekvämt att använda exponentiation-operatören ( **
) med fraktionella exponenter för att utföra nth-root-operationer, som kubrot.
Det inverse av en exponentiering är exponentiering genom exponentens ömsesidiga. Så om du kan kubera ett nummer genom att sätta det till exponenten för 3, kan du hitta kubroten till ett nummer genom att sätta det till exponenten på 1/3.
>>> x = 3
>>> y = x ** 3
>>> y
27
>>> z = y ** (1.0 / 3)
>>> z
3.0
>>> z == x
True
Beräkna stora heltalrötter
Även om Python naturligtvis stöder stora heltal kan det hända att Python misslyckas med att få den första roten till mycket stora antal.
x = 2 ** 100
cube = x ** 3
root = cube ** (1.0 / 3)
OverflowError: lång int för stor för att konvertera till float
När du hanterar så stora heltal måste du använda en anpassad funktion för att beräkna den n: a roten till ett nummer.
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