6.8. Operatori

Il primo tipo di matematica che numpy esegue su un ndarray sono gli operatori Python standard. Gli operatori aritmetici, di confronto e bit a bit funzionano tutti elemento per elemento – ogni operatore percorre l’array (o entrambi gli array) una volta dall’inizio alla fine all’interno di una singola chiamata di libreria, molto più velocemente del ciclo for Python equivalente.

6.8.1. Aritmetica

+, -, *, /, //, %, ** funzionano tutti tra due array di forma compatibile, o tra un array e uno scalare:

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

Il dtype del risultato segue le regole di upcasting descritte in Dtype. Gli array di interi vanno in overflow ciclicamente; effettua il cast a un dtype più ampio prima dell’operazione quando ciò è importante.

L’operatore di moltiplicazione di matrici @ non è implementato. Usa dot() per i prodotti matrice / vettore.

6.8.1.1. Forme in place

Ogni operatore aritmetico ha una forma in place – +=, -=, *=, /=, %=, **=. La forma in place scrive attraverso il buffer esistente invece di allocarne uno temporaneo:

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

Su un microcontrollore la seconda forma è praticamente obbligatoria per qualsiasi ciclo critico.

6.8.2. Bit a bit

Gli operatori bit a bit &, |, ^ funzionano elemento per elemento sugli array di interi. Applicati a un array float o complex sollevano 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)

L’operatore unario ~ esegue il NOT bit a bit su un array di interi.

Gli operatori di shift << e >> non sono collegati a livello di operatore Python. Le forme funzione left_shift() e right_shift() funzionano:

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

6.8.3. Confronto

==, !=, <, <=, >, >= restituiscono tutti un ndarray di tipo bool della forma risultante dal broadcast:

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

Il risultato booleano è esattamente ciò che consumano l”indicizzazione e la Selezione e riorganizzazione.

6.8.3.1. La regola del lato

Il ndarray deve trovarsi a sinistra di un operatore relazionale quando lo si confronta con uno scalare. a > 2 funziona; 2 < a solleva TypeError. Per la forma simmetrica, usa i nomi delle funzioni:

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. Operatori unari

  • +a – restituisce una copia dell’array.

  • -a – negazione. Sui dtype senza segno i valori vanno in overflow ciclicamente modulo \(2^N\), allo stesso modo degli operatori binari.

  • abs(a) – valore assoluto elemento per elemento. Sui dtype senza segno restituisce una copia senza alcun calcolo.

  • ~a – inversione bit a bit (solo array di interi).

  • len(a) – restituisce la lunghezza del primo asse, in linea con la convenzione delle sequenze Python.

6.8.5. Cosa manca

Gli operatori di destra per il confronto e per alcune operazioni bit a bit non sono implementati allo stesso modo degli operatori aritmetici. Usa le forme funzione (sopra) quando un ndarray si troverebbe a destra.

Per l’elenco completo degli operatori supportati e l’upcasting che seguono, vedi numpy — operazioni su array compatibili con numpy.