使用递归查找数字是否为2的幂

时间:2015-04-06 22:25:08

标签: python python-2.7 recursion

我试图使用递归来查找数字是否为2的幂。但是,我似乎无法找到正确的解决方案。这是我到目前为止所尝试的内容:

def is_power(n):
    n = n/2
    if n == 2:
        return True
    elif n > 2:
        is_power(n)
    else:
        return False


if is_power(32):
    print 'yes'
else:
    print 'no'

因为' 32'是2的幂,我希望我的代码返回'是'作为输出。但是,代码输出“没有”'代替。我的代码似乎有什么问题?

9 个答案:

答案 0 :(得分:22)

由于我已经在这里得到了一个接受的答案,我将用这个解释一下为什么你的方法不好:

它在python中使用递归。 Python需要为每个调用打开一个堆栈帧,因此对于非常大的数字,这将是解决此问题的一种不好的方法。对于非常大的整数,它甚至会失败。

我甚至不认为递归非纯函数式语言就像python一样直观。有一百万种更简单的方法可以做到这一点;例如,while循环:

n = int(n)
while n>1:
    if n/2 != n/2.0: #compare integer division to float division
       return False
    n = n/2
return True

通过实现计算机上整数的存储结构是:二进制,可以巧妙地完成对两个的权限的检查。因此,您可以在1的二进制表示中计算二进制int

return bin(n).count('1') == 1

也会奏效。当然,这意味着python在内部将整数转换为字符串,这会浪费大数字的内存。所以你不妨

power_of_2 = 1
while power_of_2 <= n:
    if power_of_2 == n:
        return True
    power_of_2 *= 2
return False

只需将您的数字与两个所有较小或相等的幂相比较。 (当然可能需要更长时间并且使用更多内存,因为你的python解释器必须解释python而不是仅仅将你的整数转换为C中的字符串,但这是关于算法原理的,对吧?)这样,你就不会# 39; t需要保留内存,以便在二进制表示中计算出1的出现次数。

当然,有一个解决你的问题的单线程,我从C / C ++的things I've learned写作中得到它:

bool(n and not (n&(n-1)))

要解释n and not (n&(n-1))n为真{if} n != 0,否则将错误地认定为2的幂。

对于not (n&(n-1))n&(n-1)检查某些内容是否是2的幂,所以我们必须将其反转。 &是按位&#34;和&#34;运营商。要理解n & (n-1),假设n是2的幂,让我们说8。所以n-1 == 7,因此

8|0b1000
7|0b0111
--------
&|0b0000

如您所见,对于2的所有权力,n&(n-1)0,其评估为False。对于所有2的非幂,在减去1时,您不会反转所有位,因此n&(n-1) != 0会计算为True

答案 1 :(得分:4)

elif n > 2:
    is_power(n)

缺少return

def is_power(n):
    n = n/2
    if n == 2:
        return True
    elif n > 2:
        return is_power(n)
    else:
        return False

因此,is_power的“第一”级别不会返回任何内容(或None,具体取决于您的检查方式),这会导致no的输出。

@kaveman正确地指出is_power(2)会产生错误的结果。 你可以通过在elif子句中减半2来解决这个问题:

def is_power(n):
    if not n == int(n):
        return False
    n = int(n)
    if n == 1:
        return True
    elif n > 2:
        return is_power(n/2.0)
    else:
        return False
编辑:@will指出我正在将python2与python3部门混在一起。使用/2.0修复了该问题。此外,在对该问题的评论中,他指出1是2的幂。检查==1而不是==2修复该问题。另外,我添加了一个int强制转换,这对于2次检查的功能来说不是必需的(因为,毕竟IEEE754浮点数基数为2,因此2的幂可以准确表示),但对于非2个基数,这将使代码可移植。

答案 2 :(得分:3)

上面提供的答案是错误

是的,它适用于2的幂,但它也会产生许多误报 - 因为你使用的是整数除法 - 因为你使用的是python 2.7。

如果您使用的from __future__ import division改变了/的行为,它会起作用 - 但这会改变整个程序的行为,这可能不是您想要的。

例如:

print 33/2 # 16
print 32/2 # 16

但是,使用from __future__ import division输出会更改为正确(或至少更直观)的结果 - 要获得原始整数数学行为,您需要使用//代替(如在python3中)。 / p>

所以正确答案更像是这样:

def is_power(n):
    n = n/2.0
    if n == 2:
        return True
    elif n > 2:
        return is_power(n)
    else:
        return False

请注意开头的 n= n/2.0

您需要测试您的代码是否适用于多个测试用例,而不仅仅是您想要特定结果的测试用例。

或者,我会选择这样的东西:

def is_power(n):
  if n == 2:
    return True
  elif n%2 != 0:
    return False
  else:
    return is_power(n/2.0)

答案 3 :(得分:2)

虽然这并没有直接回答你的问题,但实现这一目标的最快方法是

def is_power(n):
    return ((n & (n - 1)) == 0) and n != 0

虽然马库斯的上一篇文章已经涵盖了这一点,但有一点&#39;更多解释可能有所帮助。每个数字的二进制表示和(数字-1)共享至少一个1位,除非该数字是2的幂。此外,所有负数共享前导位,因此被此方法排除。

唯一的例外是数字0,它不与前一个数字-1共享位,并且可能不被视为2的幂。因此需要进行明确的检查。

数字的二进制表将清楚地说明这一点。

> Dcml  Binary 5bit
> -15   10001
> -14   10010
> -13   10011
> -12   10100
> -11   10101
> -10   10110
> -9    10111
> -8    11000
> -7    11001
> -6    11010
> -5    11011
> -4    11100
> -3    11101
> -2    11110
> -1    11111 
>  0    00000 
>  1    00001
>  2    00010
>  3    00011
>  4    00100
>  5    00101
>  6    00110
>  7    00111
>  8    01000
>  9    01001
>  10   01010
>  11   01011
>  12   01100
>  13   01101
>  14   01110
>  15   01111
>  16   10000

此签名数字表示法中的负数不会满足条件,因为它们共享最高有效位为1.数字0将满足条件为0&amp;(any_other_number)== 0.如果您需要实现此非常大数字你最好使用here on line 60或numpy更改dtype。此外,this guide讨论可能有助于大型数组/数字的按位运算速度。

答案 4 :(得分:1)

这是我针对某个函数的解决方案,该函数检查哪个数字是另一个数字的基数:

def is_power_of(number, base):
  # when number is smaller than base.
  if base <= 1:
    return False
  elif number < base:
    return False
  elif  number > base:
    # keep dividing number by base.
    return is_power_of(number/base, base)
  else:
    return True

答案 5 :(得分:0)

    ''''
    Power check if a number is a power of 2
    Negative numbers are not allowed
    '''
    import math
    def is_power_of_two(num):
    """

    :type num: object
    """
    try:
        x=0
        x = math.log10(num)/math.log10(2)
        return 2 ** x == num
    except ValueError:
        exit()

答案 6 :(得分:0)

这会提供一些信息,

counter = 0
def powoftwo(n):
    global counter
    counter+=1
    if n%2 != 0:
      return "Given Number %s is not Power of 2!"%g
    else:      
      if n==2:
        return "yes give number %s = 2**%s is power of 2!"%(g, counter)
      return powoftwo(n/2)

g = 1024
print powoftwo(g)

yes give number 1024 = 2**10 is power of 2!

答案 7 :(得分:0)

您可以只使用数学库的功能

import math

def isPowerOfTwo(n):
    if n <= 0:
        return False
    res = int(math.log(n) / math.log(2))
    return 2 ** res == n

答案 8 :(得分:0)

晚了,但是,另一种方式:

import math 

def is_power_of_2(x):
    n = math.log(abs(x), 2)
    return n == int(n)