6.8. Operadores

O primeiro tipo de matemática que o numpy executa sobre um ndarray são os operadores Python padrão. Os operadores aritméticos, de comparação e bit a bit funcionam todos elemento a elemento – cada operador percorre o array (ou ambos os arrays) uma vez do início ao fim numa única chamada de biblioteca, muito mais rápido do que o equivalente em Python com um ciclo for.

6.8.1. Aritmética

+, -, *, /, //, %, ** funcionam todos entre dois arrays de forma compatível, ou entre um array e um escalar:

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

O dtype do resultado segue as regras de promoção de tipo descritas em Dtypes. Arrays de inteiros envolvem em caso de overflow; converta para um dtype mais largo antes da operação quando isso for relevante.

O operador de multiplicação de matrizes @ não está implementado. Use dot() para produtos de matrizes/vetores.

6.8.1.1. Formas in-place

Cada operador aritmético tem uma forma in-place – +=, -=, *=, /=, %=, **=. A forma in-place escreve sobre o buffer existente em vez de alocar um temporário:

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

Num microcontrolador, a segunda forma é praticamente obrigatória para qualquer ciclo crítico.

6.8.2. Bit a bit

Os operadores bit a bit &, |, ^ funcionam elemento a elemento em arrays de inteiros. Aplicados a um array float ou complex levantam 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)

O operador unário ~ realiza NOT bit a bit sobre um array de inteiros.

Os operadores de deslocamento << e >> não estão ligados ao nível do operador Python. As formas funcionais left_shift() e right_shift() funcionam:

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

6.8.3. Comparação

==, !=, <, <=, >, >= devolvem todos um ndarray do tipo bool com a forma do broadcasting:

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

O resultado booleano é exatamente o que indexação e seleção consomem.

6.8.3.1. A regra do lado

O ndarray deve estar à esquerda de um operador relacional ao comparar com um escalar. a > 2 funciona; 2 < a levanta TypeError. Para a forma simétrica, use os nomes das funções:

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. Operadores unários

  • +a – devolve uma cópia do array.

  • -a – negação. Em dtypes sem sinal, os valores envolvem módulo \(2^N\), da mesma forma que os operadores binários.

  • abs(a) – valor absoluto elemento a elemento. Em dtypes sem sinal, devolve uma cópia sem cálculo.

  • ~a – inversão bit a bit (apenas arrays de inteiros).

  • len(a) – devolve o comprimento do primeiro eixo, seguindo a convenção de sequência Python.

6.8.5. O que falta

Os operadores do lado direito para as comparações e algumas das operações bit a bit não estão implementados da mesma forma que os operadores aritméticos. Use as formas funcionais (acima) quando um ndarray ficaria no lado direito.

Para a lista completa de operadores suportados e as promoções de tipo que seguem, consulte numpy — operações em arrays compatíveis com numpy.