Introducing j in Python
# The 'math' library provides many mathematical constants
# and functions for working with real numbers. Before using
# these, we must import the library.
#
# For example, the square-root function is 'sqrt(...)'.
# Because it belongs to the 'math' library, we call it by
# writing the library name, followed by a dot ('.'), followed
# by the function name:
#
#     math.sqrt(...)
#
# In Python, multiplication must always be written explicitly
# using '*'. Thus, 'a*b' is the product of 'a' and 'b', while
# 'ab' is simply a variable name.

import math


# Mathematically, these expressions are equal:
#
#   (5 + 2*sqrt(7))(5 - 2*sqrt(7))
#       = 5^2 - (2*sqrt(7))^2
#       = 25 - 28
#       = -3.
#
# Numerically, however, the first result may differ slightly
# from -3 because sqrt(7) cannot be represented exactly as a
# floating-point number.
#
# Notice that Python uses '**' for exponentiation, not '^'.

print( (5 + 2*math.sqrt(7))*(5 - 2*math.sqrt(7)) )
print( 5*5 - 2*2*7 )
print( 5**2 - 2**2*7 )


print( "\nRoots of a polynomial with real roots:" )

# Find the roots of the polynomial
#
#        2
#    3.8x  + 4.2x - 1.7.
#
# For
#
#       2
#     ax + bx + c = 0,
#
# the quadratic formula gives
#
#              2
#        -b +/- sqrt(b - 4ac)
#   x = ---------------------.
#                 2a


############################################
# Assign the variables 'a', 'b', and 'c' the
# three values shown below.
#
# Do not read
#
#     a = 3.8
#
# as "'a' equals 3.8." The '=' symbol is the
# assignment operator, so read this as
#
#     "'a' is assigned the value 3.8."
#
# After the assignment has been performed,
# 'a' does equal 3.8. To test whether two
# values are equal, however, Python uses the
# equality operator '=='.
############################################

a =  3.8
b =  4.2
c = -1.7

# Be sure to put parentheses around the denominator.
# For example,
#
#     (-b - math.sqrt(b**2 - 4*a*c))/2*a
#
# is interpreted as
#
#     ((-b - math.sqrt(b**2 - 4*a*c))/2)*a,
#
# which is not the quadratic formula.

print( (-b - math.sqrt(b**2 - 4*a*c))/(2*a) )
print( (-b + math.sqrt(b**2 - 4*a*c))/(2*a) )


print( "\nArithmetic with the imaginary unit:" )

# Python represents the imaginary unit using '1j'.
# The character 'j' by itself is simply a variable name.
#
# Thus, write '1j' for the imaginary unit. For clarity,
# parentheses can be used when raising it to a power.

print( (1j)**5 )

print( (5 + 2j)*(5 - 2j) )
print( 5*5 - 2*2*(1j)*(1j) )
print( 5**2 - (2j)**2 )


print( "\nRoots of a polynomial with complex roots:" )

# The 'math' library works with real numbers. Consequently,
# math.sqrt(...) cannot calculate the square root of a
# negative real number. For example,
#
#     math.sqrt(-1)
#
# results in
#
#     ValueError: math domain error
#
# The 'cmath' library provides corresponding mathematical
# functions for complex numbers.

import cmath

# Now find the roots of the polynomial
#
#        2
#    3.8x  + 4.2x + 1.7.
#
# Here the discriminant is negative, so the two roots
# are a complex-conjugate pair.

c = 1.7

print( (-b - cmath.sqrt(b**2 - 4*a*c))/(2*a) )
print( (-b + cmath.sqrt(b**2 - 4*a*c))/(2*a) )


############# IMPORTANT #############
# In Python, the imaginary unit must have a
# numeric coefficient:
#
#     1j
#
# You cannot write simply 'j' unless you have
# previously assigned a value to the variable
# named 'j'.
#
# More generally, Python recognizes expressions
# such as
#
#     2j
#     3.5j
#     -4j
#
# as imaginary numbers.
############# IMPORTANT #############


############# IMPORTANT #############
# The 'math' library operates on real numbers.
# Thus,
#
#     math.sqrt(-1)
#
# raises a ValueError rather than returning a
# complex number.
#
# If a calculation may require the square root
# of a negative number, use the 'cmath' library:
#
#     cmath.sqrt(-1)
#
# which returns
#
#     1j
############# IMPORTANT #############