Search code examples
pythonnth-root

check if an integer has perfect nth root - python


is_perfect is a method to check whether a number has a perfect nth root.
For example:
- is_perfect(125,3) should return True as 5^3 is 125 an integer
- is_perfect(126,3) should return False as there is no integer M for which M^3 is an integer

def is_perfect(num,power):
    root = 0.00
    p = 0.00
    float(p)
    p = 1.0/power
    root = num**(p)
    print ("root",root,sep = ' ')
    print ("root**power",root**power,sep = ' ')
    check = num -(root**power)
    print (check)
    if check < 1e-14:
        root = math.ceil(root)
    if (root-int(root)) ==0:
        print(num,root,int(root),p,sep = ' ')
        return True
    else:
        print(num,root,int(root),p,sep=' ')
        return False

In Python shell both give False when the result of 125 should be true.

>>> is_perfect(126,3)
root 5.0132979349645845
root**power 125.99999999999999
1.4210854715202004e-14
126 5.0132979349645845 5 0.3333333333333333
False
>>> is_perfect(125,3)
root 4.999999999999999
root**power 124.99999999999993
7.105427357601002e-14
125 4.999999999999999 4 0.3333333333333333
False
>>> 

How can I modify my method to achieve the desired result.


Solution

  • To avoid rounding errors in floating-point comparisons, you'll have to do some rounding and perform a final confirmation using integers:

    def is_perfect( value, exponent ):
        root = value ** ( 1.0 / exponent )
        root = long( round( root ) )
        return root ** exponent  == value
    

    To test:

    [ x for x in range( 1000 ) if is_perfect( x, 3 ) ]
    

    Output:

    [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
    

    Let's write a diagnostic test to see how high it can go:

    def test( root, exponent ):  # should print [False, True, False]
        print( [ is_perfect( root ** exponent  + i, exponent ) for i in ( -1, 0, +1 ) ] )
    

    For me, with an exponent of 19, the test fails when the root reaches somewhere in the 14 digit range. At this point when value = root**exponent is computed, value is around 900 bits long.

    test( 100000000000000, 19)  # prints [False, True, False]
    test( 999999999999999, 19)  # prints [False, False, False]