本系列測試文章索引參考 :
# Python 學習筆記索引
math 與 cmath 模組的說明文件參考 :
# https://docs.python.org/3/library/math.html
# https://docs.python.org/3/library/cmath.html
1. 匯入 math 模組 :
使用 math 模組須先匯入 :
import math
這樣呼叫 math 的方法時必須前綴模組名稱 math, 例如 math.sin(1). 也可以取一個較短的別名 (alias) :
import math as m
這樣就可以用別名 m.sin() 來呼叫函數了.
用 dir() 檢視 math 模組的成員 (屬性與方法) :
>>> import math #math 模組只能處理實數
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
用 dir() 檢視 cmath 模組的成員 (屬性與方法) :
>>> import cmath #cmath 模組可處理複數
>>> dir(cmath)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
可見大部分函數均與 math 模組一樣, 常數 e, pi, tau, nan, inf 都是相同的實數, 但 cmath 多了虛數的 infj 與 nanj.
2. math 模組中的數學常數 :
math 模組中定義了如下五個常數 (屬性) :
math 常數 | 說明 |
e | 自然指數=2.718281828459045 |
pi | 圓周率=3.141592653589793 |
tau | 圓周率的兩倍=2*pi |
nan | 非數值=float('nan') |
inf | 正無限大之浮點數=float('inf') |
其中 nan 與 inf 也可以用 float('nan') 與 float('inf') 產生, 並有對應的方法 isnan() 與 isinf() 用來檢測傳入參數是否為 nan 與 inf.
例如 :
>>> import math
>>> math.e #自然指數
2.718281828459045
>>> math.pi #圓周率
3.141592653589793
>>> math.nan #非數值
nan
>>> type(math.nan) #nan 為 float 型態
<class 'float'>
>>> float('NAN')
nan
>>> math.isnan(float('nan')) #檢查是否為 nan
True
>>> math.inf
inf
>>> type(math.inf) #inf 為 float 型態
<class 'float'>
>>> float('INF')
inf
>>> math.isinf(float('inf')) #檢查是否為 inf
True
>>> math.isnan(123) #檢查是否為 nan
False
>>> math.isinf(123) #檢查是否為 inf
False
>>> math.isnan('abc') #不可傳入字串
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be real number, not str
3. math 模組的函數 :
math 模組提供了三角, 指數, 對數, 反雙曲等超越函數如下表 :
math 方法 | 說明 |
sqrt(x) | 傳回 x 的平方根 |
pow(x, y) | 傳回 x 的 y 次方 |
exp(x) | 傳回 x 的自然指數 |
expm1(x) | 傳回 x 的自然指數-1 (在 x 接近 0 時仍有精確值) |
log(x [, b]) | 傳回 x 以 b 為基底的對數 (預設 b=e 自然對數) |
log10(x) | 傳回 x 的常用對數 (以 10 為底數) |
degrees(x) | 傳回弧度 x 的角度 (degree) |
radians(x) | 傳回角度 x 的弧度 (radian) |
dist(p, q) | 傳回兩個座標點 p, q 的歐幾里得距離 (畢式定理斜邊) |
hypot(coor) | 傳回座標序列 coor 的歐幾里得距離 |
sin(x) | 傳回 x 的正弦值 |
cos(x) | 傳回 x 的餘弦值 |
tan(x) | 傳回 x 的正切值 |
asin(x) | 傳回 x 的反正弦值 (sin 的反函數) |
acos(x) | 傳回 x 的反餘弦值 (cos 的反函數) |
atan(x) | 傳回 x 的反正切值 (tan 的反函數) |
atan2(y, x) | 傳回 y/x 的反正切值 (tan 的反函數)=atan(y/x) |
sinh(x) | 傳回 x 的雙曲正弦值 |
cosh(x) | 傳回 x 的雙曲餘弦值 |
tanh(x) | 傳回 x 的雙曲正切值 |
asinh(x) | 傳回 x 的反雙曲正弦值=log(x+sqrt(x**2+1)) |
acosh(x) | 傳回 x 的反雙曲餘弦值=log(x+sqrt(x**2-1)) |
atanh(x) | 傳回 x 的反雙曲正切值=1/2*log((1+x)/(1-x)) |
fabs(x) | 傳回 x 的絕對值 (或稱模數, modulus) |
floor(x) | 傳回浮點數 x 的向下取整數 (即小於 x 之最大整數) |
ceil(x) | 傳回浮點數 x 的向上取整數 (即大於 x 之最小整數) |
trunc(x) | 傳回浮點數 x 的整數部分 (捨去小數) |
modf(x) | 傳回浮點數 x 的 (小數, 整數) 元組 |
factorial(x) | 傳回 x 階乘 (x!, x=整數) |
gcd(x, y) | 傳回整數 x, y 之最大公因數 |
comb(n, k) | 傳回 n 取 k 的組合數 (不依序不重複) |
perm(n, k) | 傳回 n 取 k 的組合數 (依序不重複) |
modf(x, y) | 傳回 x/y 之精確餘數 (浮點數 float) |
fsum(iter) | 傳回可迭代數值 iter 之精確總和 |
isclose(x, y) | 若 a, b 值很接近傳回 True (預設差小於 1e-9) |
isfinite(x) | 若 x 不是 nan 或 inf 傳回 True, 否則 False |
isnan(x) | 若 x 為 nan 傳回 True, 否則 False |
isinf(x) | 若 x 為 inf 傳回 True, 否則 False |
例如 :
#==========數值函數測試============
>>> import math
>>> math.fabs(-1.23) #絕對值
1.23
>>> math.floor(1.5) #向下取整數
1
>>> math.floor(-1.5) #向下取整數
-2
>>> math.ceil(1.5) #向上取整數
2
>>> math.ceil(-1.5) #向上取整數
-1
>>> math.trunc(3.14159) #捨去小數部分
3
>>> math.modf(3.14159) #傳回浮點數之 (小數, 整數) 元組
(0.14158999999999988, 3.0)
>>> math.fmod(10, 3) #傳回除法餘數 (浮點數)
1.0
>>> 10 % 3 #傳回除法餘數 (整數)
1
>>> math.fsum([1, 2, 3]) #計算可迭代物件之元素和
6.0
>>> math.fsum((1, 2, 3)) #計算可迭代物件之元素和
6.0
>>> math.fsum(range(1, 11)) #計算可迭代物件之元素和
55.0
要注意 fmod() 與 modf() 的不同, fmod() 是取餘數, 表示 float modulus 之意; 而 modf() 用 Python 的取餘數運算子 % 得到的餘數為整數, 而用 math.fmod() 得到的是浮點數.
階乘函數 factorial() 在數學上 n 階乘表示為 n!=n*(n-1)*(n-2) ... *2*1, 但 0!=1!=1 :
#==========階乘函數============
>>> import math
>>> math.factorial(0)
1
>>> math.factorial(1)
1
>>> math.factorial(2)
2
>>> math.factorial(3)
6
>>> math.factorial(10)
3628800
math 官方文件中有排列函數 math.perm() 與組合函數 math.comb(), 但在 dir(math) 中卻沒有, 實際測試也確實不支援 :
>>> math.perm(8,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'math' has no attribute 'perm'
>>> math.comb(8,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'math' has no attribute 'comb'
這只好用 factorial() 來自行定義了, 排列函數 perm(n, k) 是指在 n 個不同元素中取出 k 個做排列, 總共有 n!/(n-k)! 排法 (注意, 排列是有順序的) :
def perm(n, k):
if (n<0 or k<0):
return None
else:
return math.factorial(n)/math.factorial(n-k)
組合函數 comb(n, k) 是指在 n 個不同元素中取出 k 個, 總共有 n!/[k!(n-k)!] 個取法 (注意, 組合是沒有順序的) :
def comb(n, k):
if (n<0 or k<0):
return None
else:
return math.factorial(n)/(math.factorial(k)*math.factorial(n-k))
例如 :
>>> import math
>>> def perm(n, k):
... if (n<0 or k<0):
... return None
... else:
... return math.factorial(n)/math.factorial(n-k)
...
>>> def comb(n, k):
... if (n<0 or k<0):
... return None
... else:
... return math.factorial(n)/(math.factorial(k)*math.factorial(n-k))
...
>>> perm(8,3) #8 取 3 做排列
336.0
>>> comb(49,6) #49 取 6 做組合
13983816.0
#==========指數與對數函數=============
>>> import math
>>> math.sqrt(2) #開平方
1.4142135623730951
>>> math.pow(2, 3) #次方
8.0
>>> math.exp(1) #自然指數
2.718281828459045
>>> math.expm1(1) #自然指數少 1
1.718281828459045
>>> math.e #自然指數
2.718281828459045
>>> math.log(1) #1 的對數為 0
0.0
>>> math.log(math.e) #自然指數的對數為 1
1.0
>>> math.log10(1) #1 的對數為 0
0.0
>>> math.log10(10) #常用對數
1.0
>>> math.log(8, 2) #8 以 2 為基底的對數=3, 因 2**3=8
3.0
>>> math.log(49, 7) #49 以 7 為基底的對數=2, 因 7**2=49
2.0
注意, math 模組只能處理實數, 複數需用 cmath 處理, 例如 math.sqrt(-1) 會出現 "domain error" 錯誤訊息, 但 cmath.sqrt(-1) 則會傳回 1j, 例如 :
>>> math.sqrt(-1) #math 無法處理 -1 開根號
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error
>>> cmath.sqrt(-1) #cmath 可處理 -1 開根號
1j
#==========角度與弧度轉換============
>>> import math
>>> math.degrees(math.pi) #弧度轉角度 pi=180
180.0
>>> math.degrees(math.tau) #弧度轉角度 2pi=360
360.0
>>> math.degrees(math.pi/2) #弧度轉角度 pi/2=90
90.0
>>> math.degrees(math.pi/4) #弧度轉角度 pi/4=45
45.0
>>> math.degrees(1.234) #弧度轉角度
70.70299191914359
>>> math.radians(70.703) #角度轉弧度
1.234000141037551
>>> math.radians(30) #角度轉弧度
0.5235987755982988
>>> math.radians(45) #角度轉弧度
0.7853981633974483
>>> math.radians(60) #角度轉弧度
1.0471975511965976
>>> math.radians(90) #角度轉弧度
1.5707963267948966
>>> math.radians(180) #角度轉弧度 (pi)
3.141592653589793
>>> math.radians(360) #角度轉弧度 (2pi)
6.283185307179586
三角函數是圓函數, 一共有六個, 但 math 模組只提供了三個 : sin(), cos(), 與 tan(), 因為其他三個是這三個的倒數, 即 cot=1/tan, sec=1/cos, csc=1/sin, 其反函數也是如此. 參考 :
# 維基 : 三角函數
#==========三角函數============
>>> import math
>>> math.sin(math.pi/6)
0.49999999999999994
>>> math.sin(math.pi/2)
1.0
>>> math.sin(math.pi)
1.2246467991473532e-16
>>> math.asin(1)
1.5707963267948966
>>> math.asin(0)
0.0
雙曲函數起源於解決達文西的懸鍊曲線問題 (例如吊橋與架高電纜以前被認為是拋物線, 事實上是雙曲線), 也應用在非歐幾何與相對論等. 雙曲函數跟三角函數長得很像, 函數名稱多了一個 h, 但其實與三角函數無關, 不過這兩個無關的函數在尤拉公式出現後卻統一在複變數理論下. 三角函數與雙曲函數在複平面上形狀是一樣的, 三角函數的週期是 2*pi, 而雙曲函數則是 2*pi*i.
雙曲函數定義如下 (定義域為實數) :
其實只要定義 sinh(), cosh(), 與 tanh() 即可, 另外三個只是倒數而已. 雖然雙曲函數雖然與三角函數無關, 但卻有類似三角函數之特性, 因為其公式除了正負號略為不同外均可套用, 而且在虛數圓角上與三角函數具有如下關係 :
參考 :
# 維基 : 雙曲函數
# 雙曲函數及反三角函數
# 雙曲函數的基本數性質
# 4980N031的學習歷程檔案
# 雙曲函數
# 可能是最好的讲解双曲函数的文章
# python弧度制轉換 三角函數 反三角函數 雙曲 反雙曲
#==========雙曲函數============
>>> import math
>>> math.sinh(1)
1.1752011936438014
>>> math.cosh(1)
1.5430806348152437
>>> math.tanh(1)
0.7615941559557649
>>> math.asinh(1.1752011936438014) #反雙曲正弦
1.0
>>> math.acosh(1.5430806348152437) #反雙曲餘弦
1.0
>>> math.atanh(0.7615941559557649) #反雙曲正切
0.9999999999999999
4. cmath 模組的函數 :
cmath 模組的運算元是複數, 常數增加了複數的 infj 與 nanj, 方法則大部分與 math 相同, 不過沒有階乘函數 (因為複數沒有階乘), 但增加了如下三個與複數座標轉換有關的方法, 方便在卡式座標與極座標之間轉換 :
cmath 方法 | 說明 |
polar(x) | 傳回複數 x 的極座標表示法元組 (r, p), r=長度, p=角度 |
rect(r, p) | 傳回極座標 (r, p) 的複數 |
phase(x) | 傳回複數 x 的弧度 (radian) |
#==========cmath 測試============
>>> import math
>>> import cmath
>>> print(cmath.infj)
infj
>>> print(cmath.nanj)
nanj
>>> type(cmath.nanj) #複數類型
<class 'complex'>
>>> type(cmath.nan)
<class 'float'>
>>> type(cmath.infj) #複數類型
<class 'complex'>
>>> type(cmath.inf)
<class 'float'>
>>> cmath.polar(1+1j) #複數轉極座標
(1.4142135623730951, 0.7853981633974483)>>> cmath.rect(1.4142135623730951, 0.7853981633974483)
(1.0000000000000002+1.0000000000000002j) #極座標轉直角坐標
>>> cmath.phase(1+1j) #傳回複數弧度
0.7853981633974483
>>> math.degrees(cmath.phase(1+1j)) #弧度轉角度
45.0
>>> cmath.sinh(1+1j)
(0.6349639147847361+1.2984575814159773j)
>>> cmath.cosh(1+1j)
(0.8337300251311491+0.9888977057628651j)
>>> cmath.tanh(1+1j)
(1.0839233273386946+0.2717525853195118j)
我覺得 cmath.polar() 與 cmath.rect() 在學習交流電分析時蠻好用的.
沒有留言 :
張貼留言