pythonpython-3.xrootcubepython-fractions

How to transform a cube root of a fraction into an fraction without cube root in the denominator?


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))
        

Solution

  • 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)))