检查一个数字是否是另一个数字的完美幂

时间:2016-09-01 22:10:23

标签: python math

例如,243是3的完美幂,因为243 = 3 ^ 5.

我之前一直在使用(math.log(a) / math.log(b)).is_integer(),我觉得它工作得很好,但后来我尝试了上面的例子,由于浮点运算,它实际上返回4.999999999999999。因此,对于非常小的数字,它只是可靠的,不到我发现的大约100个。

我想我可以使用循环来重复乘法...即将i设置为3,然后设置为9,然后设置为27,然后设置为81,然后设置为243,这等于目标,因此我们知道它是完美的力量。如果它达到大于243的点,那么我们就知道它不是一个完美的力量。但是我在循环中运行这个检查,所以这看起来效率很低。

那么有没有其他方法可靠地检查数字是否是另一个数字的完美力量?

7 个答案:

答案 0 :(得分:4)

尝试:

b ** int(round(math.log(a, b))) == a

也就是说,只使用log()(注意有一个2参数形式!)来猜测整数幂,然后验证"是否有效"。

注意math.log()即使对于太大而不能表示为float的整数参数,也会返回合理的结果。另请注意,Python中的整数**是精确的,并且在内部使用了一种有效的算法(执行与指数中的位数成比例的多次乘法)。

这比直接重复划分更简单,效率更高(一般而言)。

然后我回答你提出的问题;-)如果你还有其他一些问题,其他一些答案可能更合适。

答案 1 :(得分:1)

可能是这样的:

def is_perfect_power(a, b):
  while a % b == 0:
    a = a / b
  if a == 1:
    return True
  return False

print is_perfect_power(8,2)

答案 2 :(得分:1)

如果您要处理大数字,可能需要查看gmpy2gmpy2提供对GMP多精度库的访问。提供的功能之一是is_power()。如果参数是某个基数的完美幂,它将返回True。它不会提供功率或基数,但它会快速过滤掉不能完美的数字。

>>> import gmpy2
>>> [n for n in range(1,1000) if gmpy2.is_power(n)]
[1, 4, 8, 9, 16, 25, 27, 32, 36, 49, 64, 81, 100, 121, 125, 128, 144, 169, 196, 216, 225, 243, 256, 289, 324, 343, 361, 400, 441, 484, 512, 529, 576, 625, 676, 729, 784, 841, 900, 961]

一旦确定了可能的权力,就可以使用iroot_rem(x,n)来查找x的第n个根和余数。然后,一旦找到有效的指数,就可以找到基数。这是一个在范围内搜索所有可能的完美权力的例子。

>>> for x in range(1,1000):
...   if gmpy2.is_power(x):
...     for e in range(x.bit_length(), 1, -1):
...       temp_root, temp_rem = gmpy2.iroot_rem(x, e)
...       if not temp_rem:
...         print x, temp_root, e
... 
4 2 2
8 2 3
9 3 2
16 2 4
16 4 2
25 5 2
27 3 3
32 2 5
36 6 2
49 7 2
64 2 6
64 4 3
64 8 2
81 3 4
81 9 2
<< remainder clipped>>

免责声明:我保留gmpy2

答案 3 :(得分:1)

如果你想加速重复除以大数,你可以列出指数为2的幂的基数的所有指数,并仅测试它们。

例如,取3 9 。 9是二进制101,其中2 3 + 2 1 = 8 + 1.

所以3 9 = 3 8 + 1 = 3 2 3 +2 1 < / sup> = 3 2 3 x 3 2 1

你只需要试两次,而不是9次。

yourTextField.disable();

适用于正整数,例如:

def is_power(a, b):
  if b == 0 or b == 1:
    return a == b
  if a < b:
    return False
  c = []
  # make a list of the power of 2 exponents less than or equal to a:
  while b * b <= a:
    c.append(b) 
    b = b * b
  # test against each of them where b <= remaining a:
  while True: 
    if a % b != 0:
       return False
    a //= b
    while b > a:
      if len(c) == 0:
        return a == 1
      b = c.pop()
  return True

输出:

print is_power(3**554756,3)
print is_power((3**554756)-1,3)

答案 4 :(得分:0)

如果base和exponent都是通配符,那么你只能使用&#34;大数字&#34;结果,那么你将面临速度记忆的权衡。由于您似乎暗示嵌套循环效率低下并且#34;我认为CPU循环效率对您很重要。在这种情况下,我可以建议预先计算一堆基指数对:如果你愿意,可以使用一种彩虹表。这将消耗更多内存,但CPU周期更少。然后你可以简单地遍历你的桌子,看看你是否找到了匹配。或者,如果您非常关注速度,您甚至可以对表格进行排序并进行二分查找。如果愿意,您甚至可以将预先计算的表存储在文件中。

此外,您没有指定是否只需要是/否答案,或者您是否正在尝试查找相应的功率基数和指数。所以我假设你想找到一个基指数对(一些完美的权力将有多个基指数解决方案)。

尝试使用大小(我使用Python 3):

#Setup the table as a list
min_base = 2 #Smallest possible base
max_base = 100 #Largest possible base
min_exp = 2 #Smallest possible exponent
max_exp = 10 #Largest possible exponent
powers = []

#Pre-compute the table - this takes time, but only needs to be done once
for i in range(min_base, max_base+1):
    for j in range(min_exp, max_exp+1):
        powers.append([i, j, i ** j])

#Now sort the table by the 3'rd element - again this is done only once
powers.sort(key=lambda x: x[2])


#Binary search the table to check if a number is a perfect power
def is_perfect_power(a, powers_arr):
    lower = 0
    upper = len(powers_arr)
    while lower < upper:
        x = lower + (upper - lower) // 2
        val = powers_arr[x][2] #[2] for the pre-computed power
        if a == val:
            return powers_arr[x][0:2]
        elif a > val:
            if lower == x:
                break
            lower = x
        elif a < val:
            upper = x
    return False #Number supplied is not a perfect power

#A simple demonstration
print(is_perfect_power(243, powers)) #Output is [3, 5]
print(is_perfect_power(105413504, powers)) #Output is [14, 7]
print(is_perfect_power(468209, powers)) #Output is False - not a perfect power

更有数学倾向的人可能会有更有效的答案,但这应该让你开始。在我的机器上运行速度非常快。

答案 5 :(得分:0)

你也可以使用sympy的perfect_power

>>> from sympy import perfect_power
>>> perfect_power(243)
(3, 5)
>>> perfect_power(244)
False

如果您只是想检查给定数字是否是某个给定基数的完美幂,请检查下面@smichr的评论。

答案 6 :(得分:0)

def checkifanumberisapowerofanothernumber(x,y):
    if x==1:
        return y==1
    p=1
    while p<y:
        p=p*x
    return p==y

这将反复计算x的幂,直到数字接近y。然后检查数字是否等于y。