Skip to content

Python NumPy: How to Calculate Square Roots of Negative Numbers with NumPy emath

Learn how to compute mathematically correct square roots of negative numbers in NumPy using np.emath.sqrt(), which returns complex results instead of NaN.

Standard np.sqrt() returns NaN for negative inputs because it expects real number results. NumPy's emath module provides mathematically correct handling of negative and complex numbers by returning complex results.

The Problem with np.sqrt()

The standard square root function doesn't handle negative numbers:

import numpy as np

arr = np.array([4, -1, -9, 16])

result = np.sqrt(arr)
print(result)  # [ 2. nan nan  4.]

This behavior is problematic when your data legitimately contains negative values that need complex square roots.

The Solution: np.emath.sqrt()

The emath (extended math) module returns complex numbers when needed:

import numpy as np

arr = np.array([4, -1, -9, 16])

result = np.emath.sqrt(arr)
print(result)

Output:

[2.+0.j 0.+1.j 0.+3.j 4.+0.j]

Understanding the Output

import numpy as np

print(np.emath.sqrt(-1))   # 1j

print(np.emath.sqrt(-9))   # 3j

print(np.emath.sqrt(4))    # (2+0j)

print(np.emath.sqrt(-4))   # 2j

Output:

1j
3j
2.0
2j

Working with Complex Numbers

emath.sqrt() handles complex inputs correctly:

import numpy as np

complex_arr = np.array([1+2j, 3+4j, -1+0j])

result = np.emath.sqrt(complex_arr)
print(result)

print(result ** 2)

Output:

[1.27201965+0.78615138j 2.        +1.j         0.        +1.j        ]
[ 1.+2.j  3.+4.j -1.+0.j]

Extracting Real and Imaginary Parts

import numpy as np

arr = np.array([4, -1, -9, 16])
result = np.emath.sqrt(arr)

real_parts = result.real
print(f"Real parts: {real_parts}")

imag_parts = result.imag
print(f"Imaginary parts: {imag_parts}")

magnitudes = np.abs(result)
print(f"Magnitudes: {magnitudes}")

Output:

Real parts: [2. 0. 0. 4.]
Imaginary parts: [0. 1. 3. 0.]
Magnitudes: [2. 1. 3. 4.]

Other emath Functions

The emath module provides extended versions of several functions:

Logarithm of Negative Numbers

import numpy as np

print(np.log(-1))  # nan (with warning)

print(np.emath.log(-1))  # 3.141592653589793j (= iπ)


arr = np.array([1, -1, np.e, -np.e])
print(np.emath.log(arr))

Output:

RuntimeWarning: invalid value encountered in log
  print(np.log(-1))  # nan (with warning)
nan
3.141592653589793j
[0.+0.j         0.+3.14159265j 1.+0.j         1.+3.14159265j]

Power with Complex Results

import numpy as np

print(np.emath.power(-8, 1/3))  # (1+1.732j) (a complex cube root)

print(np.power(-8, 1/3))  # nan

arr = np.array([-8, -27, 8, 27])
print(np.emath.power(arr, 1/3))

Output:

(1+1.732050807568877j) nan RuntimeWarning: invalid value encountered in power print(np.power(-8, 1/3)) # nan [1. +1.73205081j 1.5+2.59807621j 2. +0.j 3. +0.j ]

Arcsin and Arccos Beyond [-1, 1]

import numpy as np

print(np.arcsin(2))        # nan

print(np.emath.arcsin(2))  # (1.5707963267948966+1.3169578969248166j)

print(np.emath.arccos(2))  # -1.3169578969248166j

Output:

RuntimeWarning: invalid value encountered in arcsin
  print(np.arcsin(2))
nan
(1.5707963267948966+1.3169578969248166j)
-1.3169578969248166j

Practical Example: Quadratic Formula

The quadratic formula can produce complex roots:

import numpy as np

def quadratic_roots(a, b, c):
    """Solve ax² + bx + c = 0, handling complex roots."""
    discriminant = b**2 - 4*a*c
    
    sqrt_disc = np.emath.sqrt(discriminant)
    
    root1 = (-b + sqrt_disc) / (2*a)
    root2 = (-b - sqrt_disc) / (2*a)
    
    return root1, root2

r1, r2 = quadratic_roots(1, -5, 6)
print(f"x² - 5x + 6 = 0: x = {r1.real}, {r2.real}")

r1, r2 = quadratic_roots(1, 0, 1)
print(f"x² + 1 = 0: x = {r1}, {r2}")

r1, r2 = quadratic_roots(1, -2, 5)
print(f"x² - 2x + 5 = 0: x = {r1}, {r2}")

Output:

x² - 5x + 6 = 0: x = 3.0, 2.0
x² + 1 = 0: x = 1j, -1j
x² - 2x + 5 = 0: x = (1+2j), (1-2j)

Converting Back to Real (When Appropriate)

If you know results should be real, extract the real part:

import numpy as np

arr = np.array([4, 9, 16, 25])

complex_result = np.emath.sqrt(arr)
print(complex_result)

real_result = complex_result.real
print(real_result)

if np.allclose(complex_result.imag, 0):
    real_result = complex_result.real

Output:

[2. 3. 4. 5.]
[2. 3. 4. 5.]

Performance Consideration

emath functions are slightly slower due to complex number handling:

import numpy as np
import timeit

arr = np.abs(np.random.randn(100000))  # Positive values only

standard_time = timeit.timeit(lambda: np.sqrt(arr), number=100)
emath_time = timeit.timeit(lambda: np.emath.sqrt(arr), number=100)

print(f"np.sqrt: {standard_time:.4f}s")
print(f"np.emath.sqrt: {emath_time:.4f}s")

Output:

np.sqrt: 0.0146s
np.emath.sqrt: 0.0229s

Summary of emath Functions

Function Standard Behavior emath Behavior
sqrt(-1) NaN 1j
log(-1) NaN πj
power(-8, 1/3) NaN Complex cube root
arcsin(2) NaN Complex result
arccos(2) NaN Complex result

Summary

Use np.emath.sqrt() when your data may contain negative numbers and you need mathematically correct complex results. The emath module extends standard NumPy functions to handle cases that would otherwise produce NaN. For purely positive data, stick with np.sqrt() for better performance.

Navigation