-1

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

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

4

3 回答 3

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

补充...:对于非常大的浮点数,floor并且ceil可能无法返回两个相邻int的 s,这可能会导致这种简单化的方法给出假阴性。这是一种不太简单的方法,即使对于巨大的数字,只要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)除了样式之外, if numis a inttoo large to convert to a仍然存在问题float(你OverflowError在那条线上得到一个)。在现实生活中,我会gmpy.root从我的旧gmpy包中使用,但另请参阅如何计算一个非常大的整数的第 n 个根以获得替代方案。

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

    float_candidate = math.exp(math.log(num)/power)

因为,特别是!,math.log(num)即使对于非常大的值也可以计算出num会导致OverflowErrorin num ** (1/power)... (!)

于 2014-12-22T17:50:14.700 回答
2

免责声明:我是@Alex Martelligmpy模块的当前维护者。当前版本被调用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、 'root等应该返回一个整数(如gmpy)还是一个浮点值?我选择添加isqrt,iroot等以返回整数值,而sqrt,root等现在返回浮点值。这遵循math模块的约定。

于 2014-12-24T17:27:50.837 回答
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,当到达 14 位范围内的某个位置test时失败。root此时value = root**exponent计算value的时间约为900 位

test( 100000000000000, 19)  # prints [False, True, False]
test( 999999999999999, 19)  # prints [False, False, False]
于 2014-12-22T18:11:08.530 回答