6.8. 運算子¶
numpy 在 ndarray 上執行的第一類數學運算是標準的 Python 運算子。算術、比較與位元運算子全都以逐元素方式運作 -- 每個運算子都在單一的函式庫呼叫中,從頭到尾走過陣列(或兩個陣列)一次,比起對等的 Python for 迴圈要快得多。
6.8.1. 算術運算¶
+、-、*、/、//、%、** 全都可在兩個形狀相容的陣列之間運作,或在一個陣列與一個純量之間運作:
a = np.array([1, 2, 3, 4], dtype=np.float)
b = np.array([10, 20, 30, 40], dtype=np.float)
print(a + b) # array([11.0, 22.0, 33.0, 44.0])
print(a * 2) # array([2.0, 4.0, 6.0, 8.0])
print(b - a) # array([9.0, 18.0, 27.0, 36.0])
print(b / a) # array([10.0, 10.0, 10.0, 10.0])
結果的 dtype 遵循 Dtype 資料型別 中所述的向上轉型(upcasting)規則。整數陣列在溢位時會繞回(wrap);當這有影響時,請在運算前先轉型為更寬的 dtype。
矩陣乘法運算子 @ 並未實作。請使用 dot() 進行矩陣/向量乘積。
6.8.1.1. 就地(in-place)形式¶
每個算術運算子都有一個就地形式 -- +=、-=、*=、/=、%=、**=。就地形式會直接寫入現有的緩衝區,而非配置一個暫存區:
b = b + 1 # allocates a temporary the size of b
b += 1 # no temporary
在微控制器上,對於任何熱迴圈而言,第二種形式基本上是必須採用的。
6.8.2. 位元運算¶
位元運算子 &、|、^ 會在整數陣列上逐元素運作。若套用於 float 或 complex 陣列,則會引發 TypeError:
a = np.array([0b1100, 0b1010], dtype=np.uint8)
b = np.array([0b1010, 0b1100], dtype=np.uint8)
print(a & b) # array([8, 8], dtype=uint8)
print(a | b) # array([14, 14], dtype=uint8)
print(a ^ b) # array([6, 6], dtype=uint8)
一元運算子 ~ 會對整數陣列執行位元 NOT 運算。
位移運算子 << 與 >> 在 Python 運算子層級並未連接實作。其函式形式 left_shift() 與 right_shift() 則可運作:
np.left_shift(a, 2)
np.right_shift(b, 1)
6.8.3. 比較運算¶
==、!=、<、<=、>、>= 全都會傳回一個廣播形狀的 bool ndarray:
a = np.array([1, 2, 3, 4, 5], dtype=np.uint8)
print(a < 3)
# array([True, True, False, False, False], dtype=bool)
6.8.3.1. 左側規則¶
與純量比較時,ndarray 必須位於關係運算子的左側。a > 2 可運作;2 < a 則會引發 TypeError。若需對稱形式,請使用函式名稱:
np.greater(5, a) # 5 > a, element-wise
np.less(5, a) # 5 < a, element-wise
np.equal(5, a) # 5 == a, element-wise
np.not_equal(5, a) # 5 != a, element-wise
6.8.4. 一元運算子¶
+a-- 傳回陣列的副本。-a-- 取負。在無號 dtype 上,值會以模 \(2^N\) 繞回,方式與二元運算子相同。abs(a)-- 逐元素絕對值。在無號 dtype 上,會傳回一份副本而不進行計算。~a-- 位元反轉(僅限整數陣列)。len(a)-- 傳回第一個軸的長度,符合 Python 序列的慣例。
6.8.5. 缺少的功能¶
比較運算與部分位元運算的右側運算子,並未以算術運算子那樣的方式實作。當 ndarray 會落在右側時,請使用(上方的)函式形式。
支援的運算子完整清單及其遵循的向上轉型規則,請參閱 numpy --- 與 numpy 相容的陣列運算。