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
>>>
如何修改我的方法以达到预期效果。
答案 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
添加了......:对于非常大的浮动广告,floor
和ceil
可能无法返回两个相邻的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
OverflowError
,gmpy.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时,test
在root
到达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_power
和gmpy2.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
)还是浮点值?我选择添加isqrt
,iroot
等来返回整数值,sqrt
,root
等现在返回浮点值。这遵循math
模块的惯例。