检查整数是否具有完美的第n个根 - python

时间:2014-12-22 17:40:20

标签: python nth-root

is_perfect是一种检查数字是否具有完美第n个根的方法 例如:
- is_perfect(125,3)应返回 True ,因为5 ^ 3是125整数
- is_perfect(126,3)应返回 False ,因为没有M ^ 3为整数的整数M

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

在Python shell中,当125的结果为真时,它们都给出False。

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

如何修改我的方法以达到预期效果。

3 个答案:

答案 0 :(得分:3)

如您所见,差异略高于您设置的严格阈值 - 例如,7.105427357601002e-14与您的1e-14阈值相比。

这是一种不同的,简单化的方法,它尽可能地使用整数,并且有效:

import math

def is_perfect(num, power):
    candidate = num ** (1/power)
    lo_candidate = int(math.floor(candidate))
    hi_candidate = int(math.ceil(candidate))
    return num == lo_candidate**power or num == hi_candidate**power

添加了......:对于非常大的浮动广告,floorceil可能无法返回两个相邻的int,这可能会导致这种简单的方法产生误报。这是一种不太简单的方法,即使对于巨大的数字也是如此,只要int(math.floor(candidate)) <= candidate(并且你有足够的内存: - )...:

def is_perfect(num, power):
    float_candidate = num ** (1/power)
    int_candidate = int(math.floor(float_candidate))
    while True:
        powered = int_candidate ** power
        if powered == num: return True
        elif powered > num: return False
        int_candidate += 1

添加** 2:这是@Kevin认为更具可读性的问题(意见问题: - )......:

import itertools

def is_perfect(num, power):
    float_candidate = num ** (1/power)
    for int_candidate in itertools.count(int(math.floor(float_candidate))):
        powered = int_candidate ** power
        if powered == num: return True
        elif powered > num: return False

如果float_candidate = num ** (1/power) num太大而无法转换为int(您获得float OverflowErrorgmpy.root仍存在问题线)。在现实生活中,我会使用我早期好gmpy套餐中的 float_candidate = math.exp(math.log(num)/power) ,但另请参阅How to compute the nth root of a very big integer

但是,值得了解的“肮脏技巧”是用第一个语句替换:

math.log(num)

因为,特别是!,num即使对于非常大的OverflowError值也可以计算,这会导致num ** (1/power)中的{{1}} ......(!)

答案 1 :(得分:2)

为避免浮点比较中的舍入错误,您必须进行一些舍入并使用整数执行最终确认:

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

测试:

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

输出:

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

让我们编写一个诊断测试,看看它有多高:

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

对我来说,当指数为19时,testroot到达14位数范围内时失败。此时计算value = root**exponent时,value的长度大于 900位

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

答案 2 :(得分:1)

免责声明:我是@Alex Martelli gmpy模块的当前维护者。当前版本名为gmpy2,可在https://code.google.com/p/gmpy/

获取

如果您可以使用外部库,则gmpy2.is_powergmpy2.iroot是您的最佳选择。

如果号码是精确的权力,

gmpy2.is_power(x)将返回True。它不会告诉你指数,但它会很快确定这些数字是确切的权力。 gmpy2.iroot(x, n)将返回一个包含整数第n个根的元组和一个布尔值,用于指示根是否正确。

>>> gmpy2.is_power(123456789123456789**19)
True
>>> gmpy2.is_power(123456789123456789**19+1)
False
>>> gmpy2.iroot(123456789123456789**19, 19)
(mpz(123456789123456789), True)
>>> gmpy2.iroot(123456789123456789**19+1, 19)
(mpz(123456789123456789), False)

gmpy2改进了对多精度浮点数的支持。这导致命名冲突:sqrt,&#39; root等应返回整数(如gmpy)还是浮点值?我选择添加isqrtiroot等来返回整数值,sqrtroot等现在返回浮点值。这遵循math模块的惯例。