How do I write a python def function that can take the cube roots of fractions and return the answer as a fraction as a coefficient with a cube root in the numerator only? I am new to coding, so I apologize if my question sounds vague. I am trying to write a program that can solve any cubic equation and return that answer in its exact form. Currently, I have a program that can do this, but it only gives the roots as a decimal.
For example, I want the answers of:
This ∛10 / ∛56 = ∛490/14 Not ∛10 / ∛56 = 0.56312394
This ∛1 / ∛27 = 1/3 Not ∛1 / ∛27 = 0.333333333
This ∛48 / ∛9 = 6∛18/9 Not ∛48 / ∛9 = 1.74716092
Basically, I just need -cubic_root(c) to be return as a fraction instead of a decimal
def cubic_root(x):
'''Compute cubic root of a number while maintaining its sign'''
if x >= 0:
return x**third #x**third means x^3
else:
return -(-x)**third
if f == g == h == 0:
x1 = -cubic_root(c) # I need this in fraction form
This is the entire code
'''
Cubic Equation Calculator (Exact Form)
By Patrick Thomas
'''
import time
import math
import fractions
goAgain = True
time.sleep(0.5)
print('')
print('Cubic Equation Calculator (Exact Form)')
time.sleep(0.5)
print('A Patman Inc. Program')
#While Loop---------------------------------------------------------------------
while goAgain == True:
time.sleep(0.5)
print('--------------------------')
print('ax³ + bx² + cx + d = 0')
print('--------------------------')
a = int(input('a = '))
b = int(input('b = '))
c = int(input('c = '))
d = int(input('d = '))
print('')
#Math---------------------------------------------------------------------------
a0 = b/a
b0 = c/a
c0 = d/a
#a0 Fraction--------------------------------------------------------------------
def a0(b,a):
if int(a) == 0:
return int(b)
return a0(int(a), int(b) % int(a))
a0_GCD = a0(b,a)
b_Simp = int(b) / a0_GCD
a_Simp = int(a) / a0_GCD
a0_frac = fractions.Fraction(int(b_Simp),int(a_Simp))
print('a0 = {}'.format(a0_frac)) #remove when finished
#b0 Fraction--------------------------------------------------------------------
def b0(c,a):
if int(a) == 0:
return int(c)
return b0(int(a), int(c) % int(a))
b0_GCD = b0(c,a)
c_Simp = int(c) / b0_GCD
a_Simp = int(a) / b0_GCD
b0_frac = fractions.Fraction(int(c_Simp),int(a_Simp))
print('b0 = {}'.format(b0_frac)) #remove when finished
#c0 Fraction--------------------------------------------------------------------
def c0(d,a):
if int(a) == 0:
return int(d)
return b0(int(a), int(d) % int(a))
c0_GCD = c0(d,a)
d_Simp = int(d) / b0_GCD
a_Simp = int(a) / b0_GCD
c0_frac = fractions.Fraction(int(d_Simp),int(a_Simp))
print('c0 = {}'.format(c0_frac)) #remove when finished
a0 = b/a
b0 = c/a
c0 = d/a
a = a0
b = b0
c = c0
# Some repeating constants and variables
third = 1./3. #Cube root
a13 = a*third #a is divided by 3
a13_num = int(b_Simp) * 1
a13_den = int(a_Simp) * 3
a13_frac = fractions.Fraction(a13_num,a13_den)
print('') #remove when finished
print('a13 (decimal) = {}'.format(a13)) #remove when finished
print('a13 (fraction) = {}'.format(a13_frac)) #remove when finished
a2 = a13*a13 #quotient of a*third times quotient of a*third
a2_num = a13_num * a13_num
a2_den = a13_den * a13_den
a2_frac = fractions.Fraction(int(a2_num),int(a2_den))
print('') #remove when finished
print('a2 (decimal) = {}'.format(a2)) #remove when finished
print('a2 (fraction) = {}'.format(a2_frac)) #remove when finished
sqr3 = math.sqrt(3)
# Additional intermediate variables
#f--------------------------------------------------------------------------
f = third * b - a2
thirdb_num = 1 * int(c_Simp)
thirdb_den = 3 * int(a_Simp)
thirdb = fractions.Fraction(thirdb_num,thirdb_den)
f_frac = thirdb - a2_frac
print('') #remove when finished
print('f (decimal) = {}'.format(f)) #remove when finished
print('f (fraction) = {}'.format(f_frac)) #remove when finished
#g--------------------------------------------------------------------------
g = a13 * (2*a2 - b) + c
paren = 2*a2 - b
two_a2_num = 2 * a2_num
two_a2_den = 1 * a2_den
two_a2_frac = fractions.Fraction(int(two_a2_num),int(two_a2_den))
parenthesis = two_a2_frac - b0_frac
g_frac = a13_frac * parenthesis + c0_frac
print('') #remove when finished
print('g (decimal) = {}'.format(g)) #remove when finished
print('g (fraction) = {}'.format(g_frac)) #remove when finished
#h--------------------------------------------------------------------------
h = 0.25*g*g + f*f*f
one_forth = fractions.Fraction(int(1),int(4))
h_frac = one_forth * g_frac * g_frac + f_frac * f_frac * f_frac
print('') #remove when finished
print('h (decimal) = {}'.format(h)) #remove when finished
print('h (fraction) = {}'.format(h_frac)) #remove when finished
#cubic_root(x)--------------------------------------------------------------
def cubic_root(x):
'''Compute cubic root of a number while maintaining its sign'''
if x >= 0:
return x**third #x**third means x^3
else:
return -(-x)**third
if f == g == h == 0:
x1 = -cubic_root(c) # I need this in fraction form
print('x₁ = {:.5f}'.format(x1))
print('x₂ = {:.5f}'.format(x1))
print('x₃ = {:.5f}'.format(x1))
elif h <= 0:
j = math.sqrt(-f)
k = math.acos(-0.5*g / (j*j*j))
m = math.cos(third*k)
n = sqr3 * math.sin(third*k)
x1 = 2*j*m - a13
x2 = -j * (m + n) - a13
x3 = -j * (m - n) - a13
print('x₁ = {:.5f}'.format(x1))
print('x₂ = {:.5f}'.format(x2))
print('x₃ = {:.5f}'.format(x3))
else:
sqrt_h = math.sqrt(h)
S = cubic_root(-0.5*g + sqrt_h)
U = cubic_root(-0.5*g - sqrt_h)
S_plus_U = S + U
S_minus_U = S - U
x1 = S_plus_U - a13
x2 = -0.5*S_plus_U - a13 + S_minus_U*sqr3*0.5j
x3 = -0.5*S_plus_U - a13 - S_minus_U*sqr3*0.5j
#x1 Section-----------------------------------------------------------------
print('') #remove when finished
print('x₁ = {:.5f}'.format(float(x1)))
#x2 Section-----------------------------------------------------------------
x2_str = str(x2)
if '+' in x2_str:
x2_part1, x2_part2 = x2_str.split('+')
x2_part1 = x2_part1.replace('(','')
x2_part2 = x2_part2.replace('j)','')
x2_part1_num = float(x2_part1)
x2_part2_num = float(x2_part2)
if float(x2_part2_num) == 0:
print('x₂ = {:.5f}'.format(x2_part1_num))
else:
print('x₂ = {:.5f} + {:.5f}i'.format(x2_part1_num,x2_part2_num))
elif '-' in x2_str:
if '(-' in x2_str:
x2_str = x2_str.replace('(-','')
x2_part1, x2_part2 = x2_str.split('-')
x2_part1 = x2_part1.replace('','-',1)
x2_part1 = x2_part1.replace('(','')
x2_part2 = x2_part2.replace('j)','')
x2_part1_num = float(x2_part1)
x2_part2_num = float(x2_part2)
if float(x2_part2_num) == 0:
print('x₂ = {:.5f}'.format(x2_part1_num))
else:
print('x₂ = {:.5f} - {:.5f}i'.format(x2_part1_num,x2_part2_num))
else:
x2_part1, x2_part2 = x2_str.split('-')
x2_part1 = x2_part1.replace('(','')
x2_part2 = x2_part2.replace('j)','')
x2_part1_num = float(x2_part1)
x2_part2_num = float(x2_part2)
if float(x2_part2_num) == 0:
print('x₂ = {:.5f}'.format(x2_part1_num))
else:
print('x₂ = {:.5f} - {:.5f}i'.format(x2_part1_num,x2_part2_num))
#x3 Section-----------------------------------------------------------------
x3_str = str(x3)
if '+' in x3_str:
x3_part1, x3_part2 = x3_str.split('+')
x3_part1 = x3_part1.replace('(','')
x3_part2 = x3_part2.replace('j)','')
x3_part1_num = float(x3_part1)
x3_part2_num = float(x3_part2)
if float(x3_part2_num) == 0:
print('x₃ = {:.5f}'.format(x3_part1_num))
else:
print('x₃ = {:.5f} + {:.5f}i'.format(x3_part1_num,x3_part2_num))
elif '-' in x3_str:
if '(-' in x3_str:
x3_str = x3_str.replace('(-','')
x3_part1, x3_part2 = x3_str.split('-')
x3_part1 = x3_part1.replace('','-',1)
x3_part1 = x3_part1.replace('(','')
x3_part2 = x3_part2.replace('j)','')
x3_part1_num = float(x3_part1)
x3_part2_num = float(x3_part2)
if float(x3_part2_num) == 0:
print('x₃ = {:.5f}'.format(x3_part1_num))
else:
print('x₃ = {:.5f} - {:.5f}i'.format(x3_part1_num,x3_part2_num))
else:
x3_part1, x3_part2 = x3_str.split('-')
x3_part1 = x3_part1.replace('(','')
x3_part2 = x3_part2.replace('j)','')
x3_part1_num = float(x3_part1)
x3_part2_num = float(x3_part2)
if float(x3_part2_num) == 0:
print('x₃ = {:.5f}'.format(x3_part1_num))
else:
print('x₃ = {:.5f} - {:.5f}i'.format(x3_part1_num,x3_part2_num))
To get rid of the cube root in the denominator, we can multiply both numerator and denominator with the square of that cube root. For example:
∛48 / ∛9 = ∛48∛9² / ∛9∛9² = ∛(48⋅9²) / 9
Then a factor should be extracted from the cube root that is a cube. For that purpose we could find all factors and then identify those that have a power of 3 or more. The powers of 3 can be extracted out of the cube root. We can either code this ourselves, or make use of sympy.ntheory.factor_.core
with t=3
, which extracts the cube-free factor, so that we can derive what the cube factor is.
In the example, we can write the fraction as:
∛(48⋅9²) / 9 = ∛(6³18) / 9 = 6∛18 / 9
The core
function will give us the 18 from 48⋅9², and from the remaining factor 6³ (which always is a perfect cube) we can derive 6.
And then finally we can divide both the coefficient part of the numerator and the denominator by their greatest common divisor (which Fraction
will do for us), and so we get:
6∛18 / 9 = 2∛18 / 3
from fractions import Fraction
from sympy.ntheory.factor_ import core # for getting the cube free factor
from sympy import integer_nthroot # for applying the integer cube-root
def rationalize(root3numerator, root3denominator):
root3numerator *= root3denominator * root3denominator
cubefree = core(root3numerator, t=3)
cube,_ = integer_nthroot(root3numerator // cubefree, 3)
return (Fraction(cube, root3denominator), cubefree)
# Helper function for formatting output
def format(fraction, root3):
strdenominator = "" if fraction.denominator == 1 else f"/{fraction.denominator}"
strroot3 = "" if root3 == 1 else f"∛{root3}"
strcoefficient = "" if fraction.numerator == 1 and strroot3 else str(fraction.numerator)
return f"{(fraction, root3)}: {strcoefficient}{strroot3}{strdenominator}"
# Example runs
for num, denom in [(10, 56), (1, 27), (48, 9), (20, 2)]:
print((num, denom), "=>", format(*rationalize(num, denom)))