6.8. Operatory

Pierwszym rodzajem matematyki, jaką numpy wykonuje na ndarray, są standardowe operatory Pythona. Operatory arytmetyczne, porównania i bitowe działają wszystkie element po elemencie – każdy operator przechodzi przez tablicę (lub obie tablice) raz od początku do końca wewnątrz pojedynczego wywołania biblioteki, znacznie szybciej niż równoważna pętla for w Pythonie.

6.8.1. Arytmetyka

+, -, *, /, //, %, ** działają wszystkie między dwiema tablicami o zgodnym kształcie albo między tablicą a skalarem:

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])

Wynikowy dtype wynika z reguł rozszerzania typów opisanych w Dtypes. Tablice całkowite zawijają się przy przepełnieniu; rzutuj na szerszy dtype przed operacją, gdy ma to znaczenie.

Operator mnożenia macierzy @ nie jest zaimplementowany. Do iloczynów macierz / wektor używaj dot().

6.8.1.1. Formy w miejscu

Każdy operator arytmetyczny ma formę w miejscu – +=, -=, *=, /=, %=, **=. Forma w miejscu zapisuje przez istniejący bufor zamiast alokować tymczasowy:

b = b + 1            # allocates a temporary the size of b
b += 1               # no temporary

Na mikrokontrolerze druga forma jest zasadniczo obowiązkowa dla każdej gorącej pętli.

6.8.2. Bitowe

Operatory bitowe &, |, ^ działają element po elemencie na tablicach całkowitych. Zastosowane do tablicy float lub complex zgłaszają 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)

Jednoargumentowy ~ wykonuje bitowe NOT na tablicy całkowitej.

Operatory przesunięcia << i >> nie są podłączone na poziomie operatora Pythona. Działają natomiast formy funkcyjne left_shift() i right_shift()

np.left_shift(a, 2)
np.right_shift(b, 1)

6.8.3. Porównanie

==, !=, <, <=, >, >= zwracają wszystkie ndarray typu bool o rozgłoszonym kształcie:

a = np.array([1, 2, 3, 4, 5], dtype=np.uint8)
print(a < 3)
# array([True, True, False, False, False], dtype=bool)

Wynik logiczny to dokładnie to, co przyjmują indeksowanie i Wybór i porządkowanie.

6.8.3.1. Reguła strony

ndarray musi znajdować się po lewej stronie operatora relacyjnego przy porównywaniu ze skalarem. a > 2 działa; 2 < a zgłasza TypeError. Dla formy symetrycznej używaj nazw funkcji:

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. Operatory jednoargumentowe

  • +a – zwraca kopię tablicy.

  • -a – negacja. Na typach bez znaku wartości zawijają się modulo \(2^N\), tak samo jak robią to operatory binarne.

  • abs(a) – wartość bezwzględna element po elemencie. Na typach bez znaku zwraca kopię bez obliczeń.

  • ~a – inwersja bitowa (tylko tablice całkowite).

  • len(a) – zwraca długość pierwszej osi, zgodnie z konwencją sekwencji w Pythonie.

6.8.5. Czego brakuje

Operatory po prawej stronie dla porównań i niektórych operacji bitowych nie są zaimplementowane w taki sam sposób jak operatory arytmetyczne. Gdy ndarray miałby wylądować po prawej stronie, używaj form funkcyjnych (powyżej).

Pełną listę obsługiwanych operatorów oraz stosowane przez nie rozszerzanie typów znajdziesz w numpy — operacje na tablicach zgodne z numpy.