The cosine triple angle formula is:
This formula, of form permits to be calculated if is known.
If is known and the value of is desired, this identity becomes:
is the solution of this cubic equation.
In fact this equation has three solutions, the other two being
It is sufficient to calculate only from accomplished by the following code:
# python codecosAfrom_cos3Adebug=0defcosAfrom_cos3A(cos3A):cos3A=Decimal(str(cos3A))+0if1>=cos3A>=-1:passelse:print('cosAfrom_cos3A(cos3A) : cos3A not in valid range.')returnNone''' if cos3A == 0 : A = 90 and cos3A = cosA if cos3A == 1 : A = 0 and cos3A = cosA if cos3A == -1 : A = 180 and cos3A = cosA'''ifcos3Ain(0,1,-1):returncos3A# From the cosine triple angle formula:a,b,c,d=4,0,-3,-cos3A# prepare for Newton's method.ifd<0:x=Decimal(1)else:x=-Decimal(1)count=31;L1=[x];almostZero=Decimal('1e-'+str(prec-2))# Newton's method:while1:count-=1ifcount<=0:print('cosAfrom_cos3A(cos3A): count expired.')breaky=a*x*x*x+c*x+difcosAfrom_cos3Adebug:print('cosAfrom_cos3A(cos3A) : x,y =',x,y)ifabs(y)<almostZero:breakslope=12*x*x+cdelta_x=y/slopex-=delta_xifxinL1[-1:-5:-1]:# This value of x has been used previously.print('cosAfrom_cos3A(cos3A): endless loop detected.')breakL1+=[x]returnx
When slope Within area of interest, maximum absolute value of slope
a rather small value for slope.
Consequently, with only 9 passes through loop, Newton's method produces a result accurate to 200 places of decimals .
There are 3 conditions, any 1 of which terminates the loop:
abs(y) very close to 0 (normal termination).
count expired.
endless loop detected with the same value of x repeated.
# python code.defcomplexCubeRoot(a,b):'''p,q = complexCubeRoot (a,b) where:* a,b are rectangular coordnates of complex number a + bi.* (p + qi)^3 = a + bi.'''a=Decimal(str(a))b=Decimal(str(b))ifa==b==0:return(Decimal(0),Decimal(0))ifa==0:return(Decimal(0),-simpleCubeRoot(b))ifb==0:return(simpleCubeRoot(a),Decimal(0))Wmod=(a*a+b*b).sqrt()wmod=simpleCubeRoot(Wmod)cosWφ=a/Wmodcoswφ=cosAfrom_cos3A(cosWφ)p=coswφ*wmod# wrealq=(wmod*wmod-p*p).sqrt()# wimag# Resolve ambiguity of q, + or -.v1=-3*p*p*q+q*q*qqp=abs(b+v1)qn=abs(b-v1)ifqp>qn:q*=-1returnp,q
# Python code used to test results of code above,defcomplexCubeRootsTest(a,b):print('\n++++++++++++++++++++')print('a,b =',a,b)almostZero=Decimal('1e-'+str(prec-5))r0,r1,r2=complexCubeRoots(a,b)forrootin(r0,r1,r2):p,q=rootprint(' pq =',(p),(q))a_,b_=(p*p*p-3*p*q*q),(3*p*p*q-q*q*q)ifa:v1=abs((a_-a)/a)ifv1>almostZero:print('error *',a_,a,v1)else:v1=abs(a_)ifv1>almostZero:print('error !',a_,a,v1)ifb:v1=abs((b_-b)/b)ifv1>almostZero:print('error &',b_,b,v1)else:v1=abs(b_)ifv1>almostZero:print('error %',b_,b,v1)returnr0,r1,r2importdecimalDecimal=D=decimal.Decimalprec=decimal.getcontext().prec# precisioncosAfrom_cos3Adebug=1forpinrange(-10,11,1):forqinrange(-10,11,1):a=p*p*p-3*p*q*qb=3*p*p*q-q*q*qcomplexCubeRootsTest(a,b)
When is given and is desired,
may be calculated from the solutions of 2 simultaneous equations:
and
For example, let
Then equations and become (for graphical purposes):
black curve in diagram, and
red curve in diagram.
Three points of intersection of red and black curves are:
and
interpreted as the three complex cube roots of namely:
and
Proof:
# python code# Each cube root cubed.>>>w0=(-18+29j)>>>w1=(34.11473670974872+1.0884572681198943j)>>>w2=(-16.11473670974872-30.088457268119896j)>>>forwin(w0,w1,w2):w**3...(39582+3799j)(39582+3799j)(39582+3799j)# The moduli of all 3 cube roots.>>>forwin(w0,w1,w2):(w.real**2+w.imag**2)**0.5...34.13209633175202434.13209633175202434.132096331752024
This method depends upon selection of most appropriate quadrant.
In the example above,
quadrant is chosen because any non-zero positive value of intersects red curve and
any non-zero negative value of intersects black curve.
Figures 1-4 below show all possibilities of and
Figure 1. When both are positive, quadrant 2 is chosen.
Figure 2. When is positive and is negative, quadrant 3 is chosen.
Figure 3. When is negative and is positive, quadrant 1 is chosen.
Figure 4. When both are negative, quadrant 4 is chosen.
defpointOfIntersection(y,a,b,quadrant):'''pointE, status = pointOfIntersection(y,a,b)y is Y coordinate of point A.'''# print('\npointOfIntersection()')t1,status=two_points(y,a,b,quadrant)ptA,ptB=t1ifstatus:# Distance between ptA and ptB is very small.# ptA is considered equivalent to the complex cube root.returnptA,statust2,status=two_points(ptB[1],a,b,quadrant)ptC,ptD=t2ifstatus:# Distance between ptC and ptD is very small.# ptC is considered equivalent to the complex cube root.returnptC,statuslineAC=line_mc(ptA,ptC)lineBD=line_mc(ptB,ptD)pointE=intersectionOf2Lines(lineAC,lineBD)returnpointE,False
defCheckMake_pq(a,b,x,y):'''p,q = CheckMake_pq(a,b,x,y)p = x and q = y.p,q are checked as valid within tolerance, and are reformatted slightly to improve appearance.'''# print ('\nCheckMake_pq(a,b,x,y)')# s1 = '(a,b)' ; print (s1,eval(s1))# s1 = ' x' ; print (s1,eval(s1))# s1 = ' y' ; print (s1,eval(s1))P=x**2;Q=y**2;p=q=-1forpin(x,):# a = ppp - 3pqq; a + 3pqq should equal ppp.ifnotalmostEqual(P*p,a+3*p*Q,Tolerance*100):continueforqin(y,):# b = 3ppq - qqq; b + qqq should equal 3ppqifnotalmostEqual(3*P*q,b+q*Q):continue# Following 2 lines improve appearance of p,qifuseDecimal:# 293.00000000000000000000000000000000000000034 becomes 293p,q=[decimal.Context(prec=precision-3).create_decimal(s).normalize()forsin(p,q)]else:# 123.99999999999923 becomes 124.0p,q=[float(decimal.Context(prec=14).create_decimal(s))forsin(p,q)]returnp,q# If code gets to here there is internal error.s1=' p';print(s1,eval(s1))s1=' q';print(s1,eval(s1))s1='P*p, a + 3*p*Q';print(s1,eval(s1))s1='3*P*q, b + q*Q';print(s1,eval(s1))1/0defComplexCubeRoot(a,b,y=100,count_=20):'''p,q = ComplexCubeRoot (a,b, y, count_)(p+qi)**3 = (a+bi)'''print('\nComplexCubeRoot(): a,b,y,count_ =',a,b,y,count_)ifuseDecimal:y,a,b=[D(str(v))forvin(y,a,b)]ifa==0:ifb==0:return0,0ifuseDecimal:cubeRoot=abs(b)**(D(1)/3)else:cubeRoot=abs(b)**(1/3)ifb>0:return0,-cubeRootreturn0,cubeRootifb==0:ifuseDecimal:cubeRoot=abs(a)**(D(1)/3)else:cubeRoot=abs(a)**(1/3)ifa>0:returncubeRoot,0return-cubeRoot,0# Select most appropriate quadrant.ifa>0:setx={2,3}else:setx={1,4}ifb>0:sety={1,2}else:sety={3,4}quadrant,=setx&sety# Make sign of y appropriate for this quadrant.ifquadrantin(1,2):y=abs(y)else:y=-abs(y)s1=' quadrant';print(s1,eval(s1))forcountinrange(0,count_):pointE,status=pointOfIntersection(y,a,b,quadrant)s1='count,status';print(s1,eval(s1))s1=' pointE[0]';print(s1,eval(s1))s1=' pointE[1]';print(s1,eval(s1))x,y=pointEifstatus:breakp,q=CheckMake_pq(a,b,x,y)returnp,q
p,q=18,-29w0=p+q*1jW=w0**3a,b=W.real,W.imags1='\na,b';print(s1,eval(s1))print('Calculate one cube root of W =',W)p,q=ComplexCubeRoot(a,b,-18)s1='\np,q';print(s1,eval(s1))sign=' + 'ifq<0:sign=' - 'print('w0 = ',str(p),sign,str(abs(q)),'i',sep='')