Python Concepts/Using Python's Decimal module

From Wikiversity
Jump to navigation Jump to search

Objective[edit]

Books-aj.svg aj ashton 01f.png
  • Learn about Python's Decimal module.
  • Learn about Decimal objects.
  • Review examples of code containing Decimal objects.
  • Learn how to use Decimal objects to perform calculations on complex numbers.
  • Become familiar with numbers containing many thousands of decimal digits.
  • Create a new class CompleX.
  • Use class CompleX and Python's Decimal module to solve the cubic equation.

Lesson[edit]

Calculations using Python's Decimal module can be performed with (almost) any precision selectable by the user. Unfortunately many functions which you might expect to find in the module don't exist, for example, trigonometric functions and functions that manipulate complex numbers. For these functions you have to find them elsewhere or write them for yourself.

Here are some examples that highlight the power of Python's Decimal Module.

Making the Decimal object[edit]

The following function verifies that we are working with Decimal objects. It provides for a tuple containing two decimal objects to simulate a complex number.

from decimal import *

getcontext().prec += 5  # Extra digits for intermediate steps.

D = Decimal

def makeDecimal (x) :
    '''
x is a single object convertible to Decimal object/s.
returns Decimal object or
        tuple containing 2 Decimal objects to simulate complex or
        exits with error status
'''

    if isinstance(x, Decimal) :
        return (x)
    if isinstance(x, int) or isinstance(x, float) :
        return (Decimal(str(x)))
    if isinstance(x, complex) :
        return ( Decimal(str(x.real)), Decimal(str(x.imag)) )
    if isinstance(x, str) :
        status = 0
        try : x1 = Decimal(x)
        except : status = -1
        if not status : return x1

        status = 0
        try : x1 = eval(x)
        except : status = -1
        if status :
            print ('makeDecimal: bad status after eval.')
            exit(79)

        if isinstance(x1, str) :
            print ('makeDecimal: eval must not produce another string.')
            exit(78)
        return makeDecimal(x1)
    print ('makeDecimal: input must be Decimal, int, float, complex or str.')
    exit(77)

Trigonometric Functions[edit]

The following trigonometric functions are sufficient to convert from complex type polar to complex type rectangular and vice-versa.

For the functions and see Recipes.

arctan [edit]

We'll try first because it's easily understood and implemented, and it can be used to calculate because the result of this expression (as in all theoretical math) is in radians.

def arctan (tanθ) : # The Python interpreter recognizes international text. Handy.
  # value returned is in radians.
  # Check input:
  x = makeDecimal (tanθ)
  if not isinstance(x, Decimal) :
      print ('arctan: type of input should be Decimal.')
      exit(79)
  
  if not x : return 0 # tan(0) = 0

  if abs(x) > 1 :
      # abs() function is valid for Decimal objects.
      print ('arctan: abs(x) should be <= 1.')
      exit(78)
  if x < 0 :
      print ('arctan: input must be >= 0.')
      exit(77) # Only non-negative values in this implementation.

  sum = x
  x_sq = x*x

  divisor = 3

  last_dividend = x

  multiplier = -1

  getcontext().prec += 2  # extra digits for intermediate steps

  almostZero = Decimal('1e-' + str(getcontext().prec))

  while 1 :
    this_dividend = last_dividend * x_sq
    if this_dividend < almostZero : break
    sum += multiplier * this_dividend / divisor

    last_dividend = this_dividend
    multiplier *= -1
    divisor += 2

  getcontext().prec -= 2  # Restore original precision.
  return sum+0 # Apply original precision to sum.

Calculating [edit]

There are many ways to calculate . For example:

Based on the following, we will perform six calculations of and compare the results.

precision = getcontext().prec
getcontext().prec = 502

tan6 = (
    ( (D('10') - D('20').sqrt()).sqrt() + D('3').sqrt() - D('15').sqrt() )
                                       /
                                       2
)
tan7_5 = D(6).sqrt() - D(3).sqrt() + D(2).sqrt() - 2
tan15 = D(2) - D(3).sqrt()
tan22_5 = D(2).sqrt() - 1
tan30 = D('3').sqrt()/3
tan36 = ( D(5) - 2*(D(5).sqrt()) ).sqrt()

values = [
(tan6, 30),
(tan7_5, 24),
(tan15, 12),
(tan22_5, 8),
(tan30, 6),
(tan36, 5)
]

L2 = [ (v[1]*arctan(v[0])).quantize(
           D('1e-'+str(getcontext().prec-3)), rounding=ROUND_HALF_UP
                                     )
           for v in values
     ]

print ('number of calculations =', len(L2))

set2 = set(L2)
len(set2) == 1 or exit(93) # All values in L2 must be equal.
π, = list(set2)
str_π = str(π)

L3 = [
str_π[start:start+70]
for start in range(0,len(str_π),70)
]

str1 = '"' + '" + \n"'.join(L3) + '"'

print (
'''
π = (
{} )
len(str(π)) = {}
isinstance(π, Decimal): {}
'''.format ( str1,
             len(str_π),
             isinstance(π, Decimal)
           )
)

getcontext().prec = precision
number of calculations = 6

π = (
"3.14159265358979323846264338327950288419716939937510582097494459230781" +
"6406286208998628034825342117067982148086513282306647093844609550582231" +
"7253594081284811174502841027019385211055596446229489549303819644288109" +
"7566593344612847564823378678316527120190914564856692346034861045432664" +
"8213393607260249141273724587006606315588174881520920962829254091715364" +
"3678925903600113305305488204665213841469519415116094330572703657595919" +
"5309218611738193261179310511854807446237996274956735188575272489122793" +
"81830119491" )
len(str(π)) = 501
isinstance(π, Decimal): True

All six calculations agree to 500 digits of precision and π is available globally as a Decimal object.

tan [edit]

.

def tanθ_2 (tanθ):
  '''
tan(θ/2) = csc θ - cot θ
x = tanθ
'''
  x = makeDecimal(tanθ)
  if not isinstance(x, Decimal) :
      print ('tanθ_2: x should be Decimal.')
      exit(76)

  if x == 0 : return 0

  if x < 0 :
      # Only non-negative values in this implementation.
      print ('tanθ_2: input < 0.')
      exit(75)

  getcontext().prec += 2  # extra digits for intermediate steps
  cscθ = ((Decimal(1)+x*x).sqrt()) / x
  cotθ = Decimal(1)/x
  tan_θ2 = cscθ - cotθ
  getcontext().prec -=2

  return (tan_θ2 + 0)

decATAN2 [edit]

For the corresponding function using floating point arithmetic see math.atan2(y, x)

This function invokes .

If and the result is

However this function invokes with a value less than so that the expression in the expansion of vanishes as rapidly as possible. Therefore:

def decATAN2 (y,x) :
  '''
               y
Input is value -.
               x
Both x,y must be convertible to Decimal object.
Only 1 of x or y may be 0.
Returns value of angle in degrees.
Value of π must be available globally.
'''
  x = makeDecimal(x)
  if not isinstance(x, Decimal) :
      print ('decATAN2: type of x',type(x),'should be Decimal.')
      exit(70)

  y = makeDecimal(y)
  if not isinstance(y, Decimal) :
      print ('decATAN2: type of y',type(y),'should be Decimal.')
      exit(69)

  if x == y == 0 :
      print ('decATAN2: both x and y cannot be 0.')
      exit(68)

  if y == 0 :
    if x > 0 : return 0
    return 180

  if x == 0 :
    if y > 0 : return 90
    return 270

  if abs(x) == abs(y) :
      if x > 0 :
          if y > 0 : return 45
          return 360-45
      if y > 0 : return 180-45
      return 180+45

  getcontext().prec += 2  # Extra digits for intermediate steps.
  tanθ = abs(y)/abs(x)

  flip = 0
  if tanθ > Decimal('3.078') : # > 72 degrees
    tanθ = 1/tanθ
    flip += 1

  reductionCount = 0
  while tanθ > Decimal('0.325') : # > 18 degrees
    tanθ = tanθ_2 (tanθ)
    reductionCount += 1

  θ = arctan(tanθ)
  if flip :
    θ = π/2 - θ
  else :
    while reductionCount :
      θ *= 2
      reductionCount -= 1

  θinDegrees = θ*180/π
  if x > 0 :
    if y < 0 :
      θinDegrees = 360-θinDegrees
  else :
    if y > 0 :
      θinDegrees = 180-θinDegrees
    else :
      θinDegrees = 180+θinDegrees

  getcontext().prec -= 2
  return θinDegrees+0

degreesToRadians (θinDegrees)[edit]

def degreesToRadians (θinDegrees) :
  '''
Value of π must be available globally.
Value returned: -π < radians <= π
-180 degrees is returned as π.
270 degrees is returned as -π/2
'''
  x = makeDecimal(θinDegrees)

  if not isinstance(x, Decimal) :
      print ('degreesToRadians: type of x should be Decimal.')
      exit(54)

  x = x % 360
  if x < 0 : x += 360
  if x > 180 : x -= 360
  return x * π/180

Complex Functions[edit]

Within the context of this page a complex number is contained in a tuple with three members, thus:

(modulus, phaseInDegrees, 'polar')

The above tuple represents complex number .

Or:

(realPart, imaginaryPart, 'rect')

where are the rectangular coordinates of complex number .

The four values are all Decimal objects.

The rectangular format is useful for addition and subtraction of complex numbers.

The polar format is useful for raising a complex number to a power including a power less than unity.

Both formats are useful for multiplication, division and square root.

When working with polar format it's generally more advantageous to work with a positive modulus. Therefore:

and, for example:

and the other sqrt of is:

.

>>> (2j)**2 ; (-2j)**2
(-4+0j)
(-4+0j)
>>>

Both of the following complex tuples equate to 0:

>>> (0,0,'rect')
>>> (0,anyNumber,'polar')

The following functions will enable us to do some serious math with complex numbers, such as solving the cubic equation with three real roots.

Administrative functions[edit]

checkComplex(x)[edit]

This function verifies that the object is a valid complex tuple.

def checkComplex(x) :
  if not isinstance(x,tuple) :
      print ('checkComplex: input type should be tuple')
      exit(69)
  if not (len(x) == 3) :
      print ('checkComplex:', 'len(x) =', len(x), 'should be 3 in', x)
      exit(68)
  if not isinstance(x[0], Decimal) :
      print ('checkComplex:', 'x[0] =', x[0], 'should be Decimal in', x)
      exit(67)
  if not isinstance(x[1], Decimal) :
      print ('checkComplex:', 'x[1] =', x[1], 'should be Decimal in', x)
      exit(66)
  if not isinstance (x[2], str) :
      print ('checkComplex: x[2] must be str.')
      exit(65)
  if (x[2] not in ('polar', 'rect')) :
      print ('checkComplex:', 'x[2] =', x[2], 'should be "polar"/"rect" in', x)
      exit(64)


makeComplex(x)[edit]

def makeComplex(x) :
  '''
Input can be tuple with 1,2 or 3 members.
If 1 or 2 members, 'rect' is understood.
The one member or single object may be int, float, complex, CompleX
or string convertible to int, float or complex.

x = makeComplex(4)
x = makeComplex((4,))
x = makeComplex(('4',0))
x = makeComplex((4,'0', 'rect'))
x = makeComplex(4+0j)
x = makeComplex('4+0j')
x = makeComplex(('4+0j',))
In all seven cases above x = ( Decimal('4'), Decimal('0'), 'rect' )

output is always
(modulus, phase, "polar") or
(real_part, imag_part, "rect")
modulus, phase, real_part, imag_part are Decimal objects.
'''
  if isinstance(x, CompleX) :  # New class CompleX (note the spelling.)
      x.check()
      return (x.r, x.i, 'rect')

  if isinstance(x, tuple) :
    if len(x) not in (1,2,3) :
        print ('makeComplex: input has wrong length.',len(x),'should be 3.')
        exit(76)
    if len(x) == 3 :
      if not isinstance (x[2], str) :
          print ('makeComplex: x[2] must be str.')
          exit(75)
      if x[2] not in ('polar','rect') :
          print ('makeComplex: type of complex in x[2] not recognized.')
          exit(75)
      v1,v2,type_ = makeComplex(x[:2])
      output = (v1,v2,x[2])
      checkComplex(output)
      return output

    if len(x) == 2 :
      v1,v2 = [ makeDecimal (v) for v in x ]
      if not isinstance(v1, Decimal) :
          print ('makeComplex: v1 should be Decimal.')
          exit(74)
      if not isinstance(v2, Decimal) :
          print ('makeComplex: v2 should be Decimal.')
          exit(73)
      output = (v1,v2, 'rect')
      return output

    x = x[0]
  t1 = makeDecimal (x)
  if isinstance(t1,Decimal) :
      output = (t1,Decimal(0),'rect')
      return output

  if (isinstance(t1, tuple) and len(t1) == 2) :
      output = t1 + ('rect',)
      checkComplex(output)
      return output

  print ('makeComplex: t1 must be tuple with length 2.')
  exit(72)

convertComplex(x)[edit]

def convertComplex(x) :
  '''
If input is rectangular, output is polar and vice-versa
'''
  x = makeComplex(x)

  if x[2] == 'polar' :
          modulus, phase = x[0], x[1]
          θinRadians = degreesToRadians (phase)
          cosθ = cos(θinRadians)
          sinθ = sin(θinRadians)
          a,b = (modulus*cosθ, modulus*sinθ)
          output = (a,b,'rect')
  else :
      real,imag = x[0], x[1]
      modulus = (real*real + imag*imag).sqrt()
      phase = decATAN2(imag, real)
      output = (modulus, phase, 'polar')

  output = makeComplex(output)
  return output

clean_complex (x)[edit]

def clean_complex (x) :
    '''
output = clean_complex (x)
output is input returned as complex tuple 
with values "cleaned".
1e-50 is returned as 0.
12.999999999999999..........9999999999999999999999
is returned as 13.
12.888888888888........8888888888888888888888888888 is left unchanged.
Note the following Decimal operations:
>>> getcontext().prec = 20
>>> Decimal('3.9999999999999999999999999999999')
Decimal('3.9999999999999999999999999999999')
>>> Decimal('3.9999999999999999999999999999999')+0
Decimal('4.0000000000000000000')
>>> (Decimal('3.9999999999999999999999999999999')+0).normalize()
Decimal('4')
>>> 
>>> Decimal(76500)
Decimal('76500')
>>> Decimal(76500).normalize()
Decimal('7.65E+4')
>>> Decimal(76500).normalize()+0
Decimal('76500')
>>> 
Hence the line: ((value+0).normalize()+0)
'''
    x = makeComplex(x)
    getcontext().prec -= 3

    almostZero = Decimal ('1e-' + str(getcontext().prec) )
    L1 = [
        ( ( (v, Decimal(0))[int(offset)] + 0 ).normalize() + 0 )
        for v in x[:2]
        for offset in (
            (v > -almostZero) and (v < almostZero),
        )
    ]

    for offset in range (0,2,1) :
        v1 = L1[offset]
        if v1 == 0 : pass
        else :
            t1 = v1.as_tuple()
            if len( t1[1] ) < getcontext().prec  : pass
            else : L1[offset] = x[offset]

    getcontext().prec += 3

    while x[2] == 'polar' :
        if L1[0] == 0 :
            L1[1] = L1[0] ; break
        if L1[0] < 0 :
            L1[0] = (L1[0]).copy_negate()
            L1[1] += 180
        L1[1] %= 360
        if L1[1] <= -180 : L1[1] += 360
        if L1[1] > 180 : L1[1] -= 360
        break

    return tuple(L1)

CompleX_to_complex (x)[edit]

def CompleX_to_complex (x) :
    '''                                                                                     
complex, float = CompleX_to_complex (x)                                                     
'''
    x = makeComplex(x)
    if x[2] == 'polar' : x = convertComplex (x)

    x = clean_complex (x)

    cx1 = complex( float(x[0]), float(x[1]) )
    fl1 = float(cx1.real)
    if cx1.imag : fl1 = None
    return (cx1, fl1)

Arithmetic functions[edit]

addComplex(v1,v2)[edit]

def addComplex(v1,v2) :
    '''
SuM = addComplex(v1,v2)
Calculation is rectangular.
The spelling of SuM indicates type CompleX.
'''
    ToP, BottoM = [ CompleX(v) for v in (v1,v2) ]

    sum = (ToP.r+BottoM.r, ToP.i+BottoM.i, 'rect')

    SuM = CompleX(sum)

    return SuM

subtractComplex(v1,v2)[edit]

def subtractComplex(v1,v2) :
    '''
DifferencE = subtractComplex(v1,v2)
where DifferencE = v1 - v2
Calculation is rectangular.
'''

    ToP, BottoM = [ CompleX(v) for v in (v1,v2) ]
    difference = (ToP.r-BottoM.r, ToP.i-BottoM.i, 'rect')
    DifferencE = CompleX(difference)

    return DifferencE

multiplyComplex (v1, v2)[edit]

def multiplyComplex (v1, v2) :
    '''
ProducT = multiplyComplex (multiplicand, multiplier)
Calculation is 'rect'.
'''

    ToP, BottoM = [ CompleX(v) for v in (v1,v2) ]
    a,b = ToP.r, ToP.i
    c,d = BottoM.r, BottoM.i
    product = ( a*c-b*d, b*c+a*d, 'rect' )
    ProducT = CompleX(product)
    return ProducT

divideComplex (dividend, divisor)[edit]

def divideComplex (dividend, divisor) :
    '''
QuotienT = divideComplex (dividend, divisor)
Calculation is 'polar'.
divisor must be non-zero.
if dividend == 0, output is 0.
'''
    DividenD, DivisoR = [ CompleX(v) for v in (dividend, divisor) ]
    if not DivisoR.m :
            print ('divideComplex: polar divisor must be non-zero.')
            exit(88)
    if (not DividenD.m) : return CompleX(0)
    quotient = (DividenD.m/DivisoR.m, DividenD.p-DivisoR.p, 'polar')
    return CompleX(quotient)

Exponential functions[edit]

complexSQRT (x)[edit]

def complexSQRT (x) :
    '''
RooT = complexSQRT (x)
calculation is 'polar'.
'''
    CX1 = CompleX(x)
    if not CX1.m : return CompleX(0)

    modulus, phase = CX1.m, CX1.p
    if modulus < 0 :
            modulus *= -1 ; phase += 180
    modulus = modulus.sqrt()
    phase = phase/2
    root = (modulus,phase,'polar')
    return CompleX(root)

complexCUBEroot (x)[edit]

def complexCUBEroot (x) :
    '''
RooT = complexCUBEroot (x)
'polar' output is useful because the other 2 cube roots are:
(root[0], root[1]+120, 'polar')
(root[0], root[1]+240, 'polar')
'''
    CX1 = CompleX(x)                                                                    
    if not CX1.m : return CompleX(0)

# Calculating the cube root is a polar operation.

    modulus, phase = CX1.m, CX1.p
    if modulus < 0 :
            modulus *= -1 ; phase += 180
    modulus_of_root = modulus ** ( Decimal(1) / Decimal(3) )
    phase_of_root = phase/3
    root = (modulus_of_root, phase_of_root, 'polar')
    RooT = CompleX(root)

    return RooT

class CompleX[edit]

class CompleX :
    '''
This class has 5 attributes:
self.r : the real coordinate of the complex number
self.i : the imaginary coordinate of the complex number
self.m : the modulus of the complex number
self.p : the phase of the complex number in degrees
self.c : the class expressed as Python type complex
'''

    def __init__(self, value=0):
        self.set(value)
        return

    def check(self) :
#        print ('entering check(self) :')
        precisions = [] ; status = 0
        for v in (self.r, self.i, self.m, self.p) :
            if not isinstance(v, Decimal) :
                print ('value not Decimal:', str(v)[:20]) ; status = -1 ; continue
            precisions += [len(v.as_tuple()[1])]
        if not isinstance(self.c, complex) :
            print ('self.c not complex:', str(self.c)[:20]) ; status = -1

        if status : exit(39)

        cx1, not_used = CompleX_to_complex ((self.r, self.i, 'rect'))
        if cx1 != self.c : print ("""
for self = {}
Rect values don't match self.c:
{}
{}""".format(
    self,cx1,self.c
            )
)
        cx1, not_used = CompleX_to_complex ((self.m, self.p, 'polar'))
        if cx1 != self.c : print ("""
for self = {}
Polar values don't match self.c:
{}
{}""".format(
    self,cx1,self.c
            )
)
        return

    def set(self, value=Decimal(0)):
#        print ('entering set(self, ',value,'):')

        t1 = makeComplex(value)
        if t1[2] == 'rect' :
            self.r, self.i = t1[:2]
            if not self.r and not self.i : self.m = self.p = Decimal(0)
            else :
                t1 = convertComplex(value)
                self.m, self.p = t1[:2]
        else :
            self.m, self.p = t1[:2]
            if not self.m : self.r = self.i = self.p = Decimal(0)
            else :
                t1 = convertComplex(value)
                self.r, self.i = t1[:2]

        self.c, not_used = CompleX_to_complex ((self.r, self.i, 'rect'))
        self.check()
        return

    def clean(self) :
#        print ('entering clean(self) :')
        self.check()
#output = clean_complex (x)                                                                 
        self.r, self.i = clean_complex ((self.r, self.i, 'rect'))
        self.m, self.p = clean_complex ((self.m, self.p, 'polar'))
        self.check()
        return

    def _print(self) :
        '''
output a string containing all the info
about self and suitable for printing.'''
        self.check()
        return '''
self = {}
real = {}
imag = {}
modulus = {}
phase = {}
as type complex: {}
'''.format(
    self,
    self.r,    self.i,
    self.m,    self.p,
    self.c,
          )

The above code highlights the power of Python in a new class called CompleX. When a new instance of this class is created, it can be accessed through its attributes and changed through its methods with the simplest of syntax.

Seemingly complicated functions such as complex cube root can be implemented in only a few lines of simple code.

Examples[edit]

CX1 = CompleX()
print ('isinstance(CX1, CompleX):', isinstance(CX1, CompleX))
print ('CX1 =', CX1._print())
isinstance(CX1, CompleX): True
CX1 =
self = <__main__.CompleX object at 0x101a463c8>
real = 0
imag = 0
modulus = 0
phase = 0
as type complex: 0j
CX2 = CompleX((5,30,'polar'))
print ('isinstance(CX2, CompleX):', isinstance(CX2, CompleX))
print ('CX2 =', CX2._print())
isinstance(CX2, CompleX): True
CX2 =
self = <__main__.CompleX object at 0x101245240>
real = 4.33012701892219323381861585376468
imag = 2.50000000000000000000000000000000
modulus = 5
phase = 30
as type complex: (4.330127018922194+2.5j)
CX3 = CompleX('-5+12j')
print ('isinstance(CX3, CompleX):', isinstance(CX3, CompleX))
print ('CX3 =', CX3._print())
isinstance(CX3, CompleX): True
CX3 =
self = <__main__.CompleX object at 0x101416f28>
real = -5.0
imag = 12.0
modulus = 13.0
phase = 112.619864948040426172949010876680
as type complex: (-5+12j)
CX2 = CX1 # shallow copy.
CX2 = CompleX(CX1) # deep copy.
CX3.check() # This should not produce error.
CX3.set(-7.5)
print ('CX3 =', CX3._print())
self = <__main__.CompleX object at 0x101415f60>
real = -7.5
imag = 0
modulus = 7.5
phase = 180
as type complex: (-7.5+0j)

Solving the cubic equation[edit]

Figure 1: Cubic function and X intercepts.

Origin at point .
Intercepts at points

The cubic equation is expressed thus: where both are non-zero.

We will solve the equation as an example of the use of Python's Decimal module and the new class CompleX. See Figure 1.

a,b,c,d = (2,1,-16,-15)

A = 2*b*b*b - 9*a*b*c + 27*a*a*d
C = b*b-3*a*c

p = -3*C
q = -A

The depressed cubic and Vieta's substitution[edit]

Let , substitute this value of in the cubic equation and produce the depressed cubic

Let , substitute this value of in the depressed equation and produce the quadratic: where .

Therefore, .

disc = q*q - 4*C*C*C

RooT = complexSQRT (disc)

DividenD = addComplex ( -q, RooT )

W = divideComplex(DividenD, 2)

isinstance(W, CompleX) or exit(48)

r = Decimal(3).sqrt()

W.clean()

print ('\n################\nW =', W._print())
################
W =
self = <__main__.CompleX object at 0x10137cbe0>
real = -665
imag = 685.892119797275408236868751236328
modulus = 955.33920677422215800938250724701
phase = 134.113967095785813976410473653471
as type complex: (-665+685.8921197972754j)

The cube roots[edit]

Figure 2: Three cube roots of W.
= RooT1; = RooT2; = RooT3.
.
Phase of
Phase of
Phase of
Phase of
RooT1 =  complexCUBEroot(W)
t1 = (RooT1.m, RooT1.p+120, 'polar')
t2 = (RooT1.m, RooT1.p-120, 'polar')
RooT2 = CompleX(t1)
RooT3 = CompleX(t2)
for root in ( RooT1, RooT2, RooT3 ) :
        root.clean()
        print ('++++++++++++++++\nRooTx:', root._print())

        print ('''
self.i
------- = {}
sqrt(3)
'''.format(
    float(root.i/r)
          )
)
# Each value of w has format (k + 1j*m*sqrt(3)). It can be shown that t = 2k.
        t = 2*root.c.real
        x = -(b+t)/(3*a)
        result = a*x*x*x + b*x*x + c*x + d
        print ('x =', x, 'result =',result)
++++++++++++++++
RooTx:
self = <__main__.CompleX object at 0x1012572e8>
real = 7
imag = 6.92820323027550917410978536602346
modulus = 9.84885780179610472174621141491761
phase = 44.7046556985952713254701578844903
as type complex: (7+6.928203230275509j)

self.i
------- = 4.0
sqrt(3)

x = -2.5 result = 0.0
++++++++++++++++
RooTx:
self = <__main__.CompleX object at 0x101257240>
real = -9.5
imag = 2.59807621135331594029116951225890
modulus = 9.84885780179610472174621141491761
phase = 164.704655698595271325470157884490
as type complex: (-9.5+2.598076211353316j)

self.i
------- = 1.5
sqrt(3)

x = 3.0 result = 0.0
++++++++++++++++
RooTx:
self = <__main__.CompleX object at 0x10136d400>
real = 2.5
imag = -9.52627944162882511440095487828231
modulus = 9.84885780179610472174621141491761
phase = -75.2953443014047286745298421155097
as type complex: (2.5-9.526279441628825j)

self.i
------- = -5.5
sqrt(3)

x = -1.0 result = 0.0

The three roots of the given cubic are .

Assignments[edit]

Crystal Clear app kedit.svg
  • Calculate the value of to 10,000 places of decimals.
 When calculating :
>>> Decimal(str(math.pi))
Decimal('3.141592653589793') # π accurate to precision 16.
>>> 
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875') # Not an accurate value of π. Why?
>>> #    3.14159265358979323846264338327950288419716939937510582097494459230781 # Correct value of π.
  • = 'polar'.
 What are the square roots of ?
  'polar' 'polar'.  'polar' =  'polar'
  • 'polar' is one of the cube roots of a certain number .
 What is the number ?
 What are the other two cube roots of ?
 
.
 The other two cube roots of  are:  'polar'
  • Given that CX1 is type CompleX, add method sqrt() to class CompleX so that the expression CX1.sqrt() returns the square root of CX1 as type CompleX.

Further Reading or Review[edit]

References[edit]

Python's built-in functions:

"abs()",

Python's documentation:

Decimal fixed point and floating point arithmetic, A first look at classes