Division of complex numbers in Python
# We have already seen addition, subtraction,
# multiplication, conjugation, and
# multiplicative inverses of complex numbers.
#
# We can now define division of complex numbers.
#
# Suppose that w and z are complex numbers and
#
# z != 0.
#
# Division by z means multiplication by the
# multiplicative inverse of z:
#
# w/z = w*(1/z).
#
# Thus, complex division follows directly from
# our definition of a multiplicative inverse.
import cmath
import math
w = 2.3 + 4.1j
z = 1.7 - 2.4j
print( "\nw:" )
print( w )
print( "\nz:" )
print( z )
print( "\nw/z:" )
print( w/z )
print( "\nw*(1/z):" )
print( w*(1/z) )
# Apart from possible floating-point rounding,
# these last two values are the same.
# We can derive a formula for division in terms
# of the real and imaginary components.
#
# Suppose
#
# w = a + bj
#
# and
#
# z = c + dj.
#
# We want to calculate
#
# a + bj
# ------.
# c + dj
#
# Recall that the multiplicative inverse of z is
#
# 1 c - dj
# ------ = ---------.
# c + dj c^2+d^2
#
# Therefore,
#
# a + bj
# ------
# c + dj
#
# c - dj
# = (a + bj) --------
# c^2+d^2
#
# (a + bj)(c - dj)
# = -----------------.
# c^2+d^2
#
# Multiplying out the numerator gives
#
# (a + bj)(c - dj)
#
# = ac + bd + (bc - ad)j.
#
# Therefore,
#
# a + bj
# ------
# c + dj
#
# ac + bd bc - ad
# ------- + ------- j.
# c^2+d^2 c^2+d^2
# Let us verify this formula.
a = w.real
b = w.imag
c = z.real
d = z.imag
quotient_formula = (
(a*c + b*d)/(c**2 + d**2)
+ 1j*(b*c - a*d)/(c**2 + d**2)
)
print( "\nw/z calculated directly:" )
print( w/z )
print( "\nw/z calculated from the components:" )
print( quotient_formula )
# Another way to derive the same result is to
# multiply the numerator and denominator by the
# complex conjugate of the denominator:
#
# w w*conj(z)
# - = ---------.
# z z*conj(z)
#
# Recall that
#
# 2
# z*conj(z) = |z|.
#
# Thus,
#
# w w*conj(z)
# - = ----------.
# z 2
# |z|
#
# This is often the most useful general formula
# for complex division.
#
# In Python, the complex conjugate of z is
#
# z.conjugate().
print( "\nw/z:" )
print( w/z )
print( "\nw*z.conjugate()/abs(z)**2:" )
print( w*z.conjugate()/abs(z)**2 )
# Notice that the denominator
#
# 2
# |z|
#
# is a positive real number whenever z != 0.
#
# Multiplying by the conjugate has therefore
# removed the complex number from the
# denominator.
# Division has many useful properties.
#
# First, dividing a number by itself gives 1,
# provided the number is nonzero:
#
# z/z = 1.
print( "\nz/z:" )
print( z/z )
# Dividing by 1 leaves a number unchanged:
#
# z/1 = z.
print( "\nz/1:" )
print( z/1 )
# Dividing zero by any nonzero number gives
# zero:
#
# 0/z = 0.
print( "\n0/z:" )
print( 0/z )
# Division by zero, however, is not defined.
#
# Thus, an expression such as
#
# w/0
#
# does not represent a complex number.
#
# In Python, attempting to evaluate it causes
# a ZeroDivisionError.
# Division is not commutative.
#
# In general,
#
# w/z != z/w.
print( "\nw/z:" )
print( w/z )
print( "\nz/w:" )
print( z/w )
# Division is also not associative.
#
# In general,
#
# (w/z)/v != w/(z/v).
v = -0.8 + 1.3j
print( "\n(w/z)/v:" )
print( (w/z)/v )
print( "\nw/(z/v):" )
print( w/(z/v) )
# In fact,
#
# (w/z)/v = w/(z*v),
#
# while
#
# w/(z/v) = w*v/z.
print( "\n(w/z)/v and w/(z*v):" )
print( (w/z)/v )
print( w/(z*v) )
print( "\nw/(z/v) and w*v/z:" )
print( w/(z/v) )
print( w*v/z )
# Conjugation works particularly nicely with
# division.
#
# The conjugate of a quotient is the quotient
# of the conjugates:
#
# / w \ conj(w)
# conj( | - | ) = -------.
# \ z / conj(z)
#
# provided z != 0.
#
# In Python, this is
#
# (w/z).conjugate()
#
# and
#
# w.conjugate()/z.conjugate().
print( "\nConjugate of w/z:" )
print( (w/z).conjugate() )
print( "\nw.conjugate()/z.conjugate():" )
print( w.conjugate()/z.conjugate() )
# This follows from the corresponding
# properties for multiplication and
# multiplicative inverses.
# Multiplicative inverses also work naturally
# with division.
#
# Recall that we represent the multiplicative
# inverse of a scalar z by
#
# 1/z.
#
# The inverse of a quotient is
#
# 1
# -----
# w/z
#
# z
# = -.
# w
#
# Thus,
#
# 1
# -----
# w/z
#
# 1/w
# = -----.
# 1/z
#
# In other words,
#
# inverse(w/z)
#
# = inverse(w)/inverse(z).
print( "\nInverse of w/z:" )
print( 1/(w/z) )
print( "\nz/w:" )
print( z/w )
print( "\n(1/w)/(1/z):" )
print( (1/w)/(1/z) )
# Magnitudes also behave very simply under
# division.
#
# The magnitude of a quotient is the quotient
# of the magnitudes:
#
# |w/z| = |w|/|z|.
print( "\nabs(w/z):" )
print( abs(w/z) )
print( "\nabs(w)/abs(z):" )
print( abs(w)/abs(z) )
# This follows immediately from
#
# w/z = w*(1/z)
#
# together with
#
# |w*z| = |w|*|z|
#
# and
#
# |1/z| = 1/|z|.
# Arguments also have a simple relationship.
#
# Multiplication adds arguments, while division
# subtracts them:
#
# arg(w/z)
#
# = arg(w) - arg(z) modulo 2*pi.
#
# Because cmath.phase(...) returns a principal
# argument, the two numerical values may differ
# by a multiple of 2*pi.
print( "\nphase(w/z):" )
print( cmath.phase(w/z) )
print( "\nphase(w) - phase(z):" )
print( cmath.phase(w) - cmath.phase(z) )
# The same relationship can be expressed in
# degrees:
#
# arg(w/z)
#
# = arg(w) - arg(z) modulo 360 deg.
print( "\nphase(w/z) in degrees:" )
print( math.degrees(cmath.phase(w/z)) )
print( "\nphase(w) - phase(z) in degrees:" )
print(
math.degrees(cmath.phase(w))
- math.degrees(cmath.phase(z))
)
# Geometrically, division therefore has two
# effects.
#
# If
#
# w = |w| exp(j*alpha)
#
# and
#
# z = |z| exp(j*beta),
#
# then
#
# w |w|
# - = --- exp(j*(alpha - beta)).
# z |z|
#
# Thus, dividing by z:
#
# 1. divides the magnitude by |z|, and
#
# 2. subtracts the argument of z.
#
# Equivalently, dividing by z scales by
#
# 1/|z|
#
# and rotates by
#
# -arg(z).
# There are also several useful algebraic
# identities involving division.
#
# Provided all denominators are nonzero,
#
# (w*z)/z = w.
print( "\n(w*z)/z:" )
print( (w*z)/z )
print( "\nw:" )
print( w )
# Multiplication can be applied to both the
# numerator and denominator:
#
# (w*v)/(z*v) = w/z
#
# provided v != 0.
print( "\n(w*v)/(z*v):" )
print( (w*v)/(z*v) )
print( "\nw/z:" )
print( w/z )
# Division distributes over addition and
# subtraction in the numerator:
#
# (w + v)/z = w/z + v/z
#
# and
#
# (w - v)/z = w/z - v/z.
print( "\n(w + v)/z:" )
print( (w + v)/z )
print( "\nw/z + v/z:" )
print( w/z + v/z )
print( "\n(w - v)/z:" )
print( (w - v)/z )
print( "\nw/z - v/z:" )
print( w/z - v/z )
# Be careful: division does NOT distribute over
# addition in the denominator.
#
# In general,
#
# w w w
# ----- != --- + ---.
# z + v z v
print( "\nw/(z + v):" )
print( w/(z + v) )
print( "\nw/z + w/v:" )
print( w/z + w/v )
# Quotients can also be multiplied:
#
# w u w*u
# - * - = ---.
# z v z*v
u = 3.2 - 0.6j
print( "\n(w/z)*(u/v):" )
print( (w/z)*(u/v) )
print( "\n(w*u)/(z*v):" )
print( (w*u)/(z*v) )
# Dividing one quotient by another gives
#
# w/z w*v
# --- = ---.
# u/v z*u
#
# This is the familiar rule of multiplying by
# the reciprocal.
print( "\n(w/z)/(u/v):" )
print( (w/z)/(u/v) )
print( "\n(w*v)/(z*u):" )
print( (w*v)/(z*u) )
# Integer powers also behave naturally with
# division:
#
# n
# (w/z)
#
# n
# w
# = --.
# n
# z
#
# This holds for integer n whenever the
# expressions involved are defined.
#
# Recall that exponentiation in Python uses
# '**', not '^'.
n = 4
print( "\n(w/z)**n:" )
print( (w/z)**n )
print( "\nw**n/z**n:" )
print( w**n/z**n )
# We can summarize the most important
# properties of complex division as follows.
#
# Division by z is multiplication by its
# multiplicative inverse:
#
# w/z = w*(1/z).
#
# The conjugate of a quotient is
#
# conj(w)
# conj(w/z) = ---------.
# conj(z)
#
# In Python:
#
# (w/z).conjugate()
#
# = w.conjugate()/z.conjugate().
#
# The inverse of a quotient is
#
# 1 z 1/w
# ----- = - = -----.
# w/z w 1/z
#
# The magnitude of a quotient is
#
# |w|
# |w/z| = -----.
# |z|
#
# The argument of a quotient is
#
# arg(w/z)
#
# = arg(w) - arg(z) modulo 2*pi.
#
# Thus, geometrically, division divides
# magnitudes and subtracts arguments.