Skip to content

NumPy - Arithmetic Operations

NumPy excels at performing fast, element-wise arithmetic operations on arrays. These operations are implemented as universal functions (ufuncs), which operate on ndarray objects efficiently.

For arithmetic operations between two arrays (e.g., a + b, a * b), NumPy requires the arrays to either have the exact same shape or be compatible according to the broadcasting rules. Broadcasting allows NumPy to implicitly expand the smaller array to match the shape of the larger array, enabling element-wise operations even when shapes don’t perfectly align. (Learn more about Broadcasting)

Standard Python arithmetic operators (+, -, *, /, **, //, %) are overloaded by NumPy to perform element-wise operations on arrays. This is often the most readable way to express calculations.

Example: Element-wise operations with Broadcasting

Section titled “Example: Element-wise operations with Broadcasting”
import numpy as np
# Create a 3x3 array
a = np.arange(9, dtype=np.float64).reshape(3, 3)
print(f"First array (a):\n{a}\n")
# Create a 1D array (compatible for broadcasting with 'a')
b = np.array([10., 100., 1000.])
print(f"Second array (b): {b}\n")
# Element-wise addition (b is broadcast across rows of a)
print(f"Add a + b:\n{a + b}\n")
# Element-wise subtraction
print(f"Subtract a - b:\n{a - b}\n")
# Element-wise multiplication
print(f"Multiply a * b:\n{a * b}\n")
# Element-wise division
print(f"Divide a / b:\n{a / b}\n")

Output:

First array (a):
[[0. 1. 2.]
[3. 4. 5.]
[6. 7. 8.]]
Second array (b): [ 10. 100. 1000.]
Add a + b:
[[ 10. 101. 1002.]
[ 13. 104. 1005.]
[ 16. 107. 1008.]]
Subtract a - b:
[[ -10. -99. -998.]
[ -7. -96. -995.]
[ -4. -93. -992.]]
Multiply a * b:
[[ 0. 100. 2000.]
[ 30. 400. 5000.]
[ 60. 700. 8000.]]
Divide a / b:
[[0. 0.01 0.002]
[0.3 0.04 0.005]
[0.6 0.07 0.008]]

NumPy also provides explicit ufuncs for these operations (e.g., np.add, np.subtract, np.multiply, np.divide), which can sometimes offer more control or options via specific arguments.

Computes the element-wise reciprocal (1/x). Be aware of division by zero, which results in inf (infinity) and raises a RuntimeWarning.

import numpy as np
a = np.array([0.25, 1.33, 1., 0., -2.], dtype=np.float64)
print(f"Original array: {a}\n")
# Calculate reciprocal
reciprocal_a = np.reciprocal(a)
print(f"Reciprocal: {reciprocal_a}")
# Example with an integer (results in 0 for integers > 1)
int_arr = np.array([100], dtype=int)
print(f"\nInteger array: {int_arr}")
print(f"Reciprocal of integer: {np.reciprocal(int_arr)}") # Output: [0]

Output (warning omitted for brevity):

Original array: [ 0.25 1.33 1. 0. -2. ]
Reciprocal: [ 4. 0.7518797 1. inf -0.5 ]
Integer array: [100]
Reciprocal of integer: [0]

Raises elements of the first array to the power of corresponding elements in the second array (or a scalar).

import numpy as np
a = np.array([1, 2, 3])
print(f"Base array (a): {a}")
# Square each element
print(f"a squared (a ** 2): {np.power(a, 2)}")
# Raise elements to different powers
b = np.array([1, 2, 3])
print(f"Exponent array (b): {b}")
print(f"a raised to power b: {np.power(a, b)}")

Output:

Base array (a): [1 2 3]
a squared (a ** 2): [1 4 9]
Exponent array (b): [1 2 3]
a raised to power b: [ 1 4 27]

Computes the element-wise remainder of division. np.mod() and np.remainder() are equivalent for positive values; they may differ slightly for negative values based on convention.

import numpy as np
a = np.array([10, 20, 30])
b = np.array([3, 5, 7])
print(f"First array (a): {a}")
print(f"Second array (b): {b}\n")
print(f"Remainder using np.mod(a, b): {np.mod(a, b)}")
print(f"Remainder using np.remainder(a, b): {np.remainder(a, b)}")

Output:

First array (a): [10 20 30]
Second array (b): [3 5 7]
Remainder using np.mod(a, b): [1 0 2]
Remainder using np.remainder(a, b): [1 0 2]

NumPy seamlessly handles arrays with complex data types (np.complex64, np.complex128). Specific functions are available to extract parts of complex numbers:

  • numpy.real(): Returns the real part.
  • numpy.imag(): Returns the imaginary part.
  • numpy.conj() or numpy.conjugate(): Returns the complex conjugate (changes the sign of the imaginary part).
  • numpy.angle(): Returns the angle (in radians by default, or degrees if deg=True).
import numpy as np
# Note: Use 'j' for the imaginary unit in Python
c = np.array([-5.6j, 0.2j, 11., 1 + 1j])
print(f"Complex array: {c}\n")
print(f"Real part: {np.real(c)}")
print(f"Imaginary part: {np.imag(c)}")
print(f"Conjugate: {np.conj(c)}")
print(f"Angle (radians): {np.angle(c)}")
print(f"Angle (degrees): {np.angle(c, deg=True)}")

Output:

Complex array: [ 0.-5.6j 0.+0.2j 11.+0.j 1.+1.j ]
Real part: [ 0. 0. 11. 1.]
Imaginary part: [-5.6 0.2 0. 1. ]
Conjugate: [ 0.+5.6j 0.-0.2j 11.-0.j 1.-1.j ]
Angle (radians): [-1.57079633 1.57079633 0. 0.78539816]
Angle (degrees): [-90. 90. 0. 45.]

For a full list of universal functions, refer to the NumPy ufunc documentation.