How to Calculate Square Root of Negative Numbers in Python
By default, calculating the square root of a negative value using the standard math library raises a ValueError: math domain error. This is because real number mathematics doesn't define square roots for negatives. To handle this, you need complex numbers using Python's specialized modules.
Single Values with cmath
The cmath (complex math) module is part of the standard library and returns complex results when appropriate:
import cmath
val = -16
result = cmath.sqrt(val)
print(f"Result: {result}") # (4j)
print(f"Real part: {result.real}") # 0.0
print(f"Imaginary part: {result.imag}") # 4.0
Python uses j (engineering notation) instead of i to represent √-1. Access components with .real and .imag attributes.
Comparison with math Module
import math
import cmath
# ❌ Raises ValueError
try:
math.sqrt(-16)
except ValueError as e:
print(f"math.sqrt error: {e}")
# ✅ Returns complex number
result = cmath.sqrt(-16)
print(f"cmath.sqrt result: {result}") # 4j
Output:
math.sqrt error: math domain error
cmath.sqrt result: 4j
Arrays with numpy.emath
For NumPy arrays, regular np.sqrt() returns nan for negative values. Use np.emath.sqrt() for complex support:
import numpy as np
arr = np.array([4, -4, 25, -25])
# Regular sqrt: returns nan for negatives
regular = np.sqrt(arr)
print(f"np.sqrt: {regular}")
# [2. nan 5. nan] with RuntimeWarning
# emath: returns complex numbers
complex_result = np.emath.sqrt(arr)
print(f"np.emath.sqrt: {complex_result}")
# [2.+0.j 0.+2.j 5.+0.j 0.+5.j]
Output:
<main.py>:6: RuntimeWarning: invalid value encountered in sqrt
np.sqrt: [ 2. nan 5. nan]
np.emath.sqrt: [2.+0.j 0.+2.j 5.+0.j 0.+5.j]
Regular np.sqrt() issues a RuntimeWarning but continues with nan values. This can silently corrupt your data pipeline. Use emath when negative inputs are possible.
Working with Complex Results
import cmath
result = cmath.sqrt(-9) # 3j
# Extract components
print(f"Real: {result.real}") # 0.0
print(f"Imaginary: {result.imag}") # 3.0
print(f"Magnitude: {abs(result)}") # 3.0
print(f"Phase: {cmath.phase(result)}") # 1.5707... (π/2 radians)
# Verify: (3j)² = -9
print(f"Squared: {result ** 2}") # (-9+0j)
Output:
Real: 0.0
Imaginary: 3.0
Magnitude: 3.0
Phase: 1.5707963267948966
Squared: (-9+0j)
Creating Complex Numbers
# Literal notation
z1 = 3 + 4j
# Using complex()
z2 = complex(3, 4)
# From square root
import cmath
z3 = cmath.sqrt(-25) # 5j
print(z1, z2, z3)
Output:
(3+4j) (3+4j) 5j
Library Comparison
| Module | Result for √-1 | Use Case |
|---|---|---|
math | ❌ ValueError | Real numbers only |
cmath | ✅ 1j | Single complex values |
numpy | 🟡 nan + warning | Clean real-number arrays |
numpy.emath | ✅ 1j | Mixed arrays with negatives |
Quick Reference
| Goal | Method |
|---|---|
| Single negative sqrt | cmath.sqrt(x) |
| Array with negatives | np.emath.sqrt(arr) |
| Get real part | result.real |
| Get imaginary part | result.imag |
| Get magnitude | abs(result) |
Summary
Use cmath.sqrt() for single negative values, it returns proper complex numbers instead of raising errors. For NumPy arrays with potential negative values, use np.emath.sqrt() to avoid silent nan corruption. Both modules seamlessly handle the transition between real and complex results.