【问题标题】:How do I decompose a number into powers of 2?如何将数字分解为 2 的幂?
【发布时间】:2015-05-15 03:15:46
【问题描述】:

我正在尝试创建一个函数,它接收一个数字作为参数并对该数字执行操作,以找出其最接近的 2 的幂,然后将其加起来为该数字。例如,如果用户输入 4,函数将附加 4,因为它已经是 2 的幂。如果用户输入 14,函数应该看到 14 不是 2 的幂,并且组成最接近的 2 幂14 是 2,4 和 8。

主要说明: 我最多只能达到 2^9。

到目前为止我有什么:

def powers_finder(n):
    powers=[]
    i=0
    total=0
    while i<10:
         value=2**i
         total=total+value
         i=i+1
         #This if statement is for if the user enters a power of 2 as n
         #Then the number will be appended right away into my powers list.
         if value==n:
            powers.append(value)

这里的问题是如果用户输入让我们说 5 因为 (n) 5 由 2^2=4 和 2^0=1 4+1=5 的幂组成。如何扩展我的功能以包含此过程?

谢谢!

【问题讨论】:

  • 把数字转换成二进制怎么样?
  • 2 的最接近的幂是多少?
  • 我相信这个练习应该教你二进制算术的基础知识。没有任何答案不会破坏这一课。
  • @njzk2 我的意思是如果用户输入 3 那么我的函数需要附加 2 和 1.... 2^0=1 和 2^2=2....2 +1=3 所以我的列表里面会有一个 2 和一个 1。如果用户输入的数字已经是 2 的幂,那么该函数会立即将其附加到列表中。
  • 你的意思是分解为 2 的唯一幂吗? (如,任何 2 的幂只能出现一次?否则,n*2^0 = n,bam 解决了)

标签: python python-3.x


【解决方案1】:

最有效的方法:

def myfunc(x):
    powers = []
    i = 1
    while i <= x:
        if i & x:
            powers.append(i)
        i <<= 1
    return powers

【讨论】:

  • 作为tested,这是迄今为止最快的解决方案。
【解决方案2】:

尝试使用二进制文件:

def power_find(n):
    result = []
    binary = bin(n)[:1:-1]
    for x in range(len(binary)):
        if int(binary[x]):
            result.append(2**x)
    return result

>>> power_find(11)
[1, 2, 8]

【讨论】:

  • 也可以缩减为一行,但是会导致一行很长。
  • 说实话,我以前从未见过这样的做法......这似乎也是最短和最简单的方式。开始通过 python int 到二进制转换并尝试尝试自己重建它!
【解决方案3】:

下面的二进制解决方案结合了@moose 对enumerate() 的使用与@gbriones.gdl 对步幅索引的使用以及@gbriones.gdl 关于单衬的评论(实际上,这是关于not 单衬,但单衬很有趣)。

def powers(n):
    return [2**p for p,v in enumerate(bin(n)[:1:-1]) if int(v)]

【讨论】:

    【解决方案4】:

    当然,最好和最快的方法是使用二进制数,但这里有一种使用生成器的方法:

    def powers_finder(num):
        d = []
        while sum(d) < num:
            p = powers_of_2()
            a=b=1
            while sum(d)+a<=num:
                b=a
                a = next(p)
            d.append(b)
        d.reverse()
        return d
    
    def powers_of_2():
        n=1
        while 1:
            yield n
            n*=2
    

    >>> print(powers_finder(5))
    [1, 4]
    >>> print(powers_finder(8))
    [8]
    >>> print(powers_finder(9))
    [1, 8]
    >>> print(powers_finder(14))
    [2, 4, 8]
    

    【讨论】:

      【解决方案5】:

      一种简单(但实际上并不有效)的方法是使用回溯。请注意,使用math.log 函数很容易找到最接近的二的幂(n 的二的最接近幂是2^round(log(n, 2))):

      from math import log
      
      def powers_finder(n):
          return powers_finder_rec(n, [2**x for x in range(round(log(n, 2)+1))])
      
      def powers_finder_rec(n, powers):
          if sum(powers) == n:
              return powers
      
          for i, j in enumerate(powers):
              (res1, res2) = (powers_finder_rec(n-j, powers[:i] + powers[i+1:]),  
                                          powers_finder_rec(n, powers[:i] + powers[i+1:]))
              if res1 or res2:
                  return [j] + res1 if res1 else res2
      
          return []
      
      print(powers_finder(13))
      print(powers_finder(112))
      

      输出:

      [1, 4, 8]
      [16, 32, 64]
      

      【讨论】:

        【解决方案6】:

        对于这个问题,我们现在有了一些不错的答案。我想我会用distimeit 对它们进行一些分析。

        这是我使用的测试代码:

        import dis
        import timeit
        
        def gbriones_gdl(num):
            result = []
            binary = bin(num)[:1:-1]
            for x in range(len(binary)):
                if int(binary[x]):
                    result.append(2**x)
            return result
        
        def nullptr(num):
            powers = []
            i = 1
            while i <= num:
                if i & num:
                    powers.append(i)
                i <<= 1
            return powers
        
        def t3_gen(num):
            d = []
            while sum(d) < num:
                p = powers_of_2()
                a=b=1
                while sum(d)+a<=num:
                    b=a
                    a = next(p)
                d.append(b)
            d.reverse()
            return d
        
        def powers_of_2():
            n=1
            while 1:
                yield n
                n*=2
        
        def t3_enum(num):
            return [2**p for p,v in enumerate(bin(num)[:1:-1]) if int(v)]
        
        def moose(num):
            get_bin = lambda x: x >= 0 and str(bin(x))[2:] or "-" + str(bin(x))[3:]
            bin_str = get_bin(num)  # convert num to a binary string
            powers = []
            for i, digit in enumerate(bin_str[::-1]):
                if digit == '1':
                    powers.append(2**i)
            return powers
        
        print('Each function gives correct results:', nullptr(1048575) == moose(1048575) ==
        t3_enum(1048575) == gbriones_gdl(1048575) ==
        t3_gen(1048575))
        print()
        
        print('nullptr'.ljust(15), timeit.timeit('nullptr(1048575)', 'from __main__ import nullptr', number=100000))
        print('moose'.ljust(15), timeit.timeit('moose(1048575)', 'from __main__ import moose', number=100000))
        print('t3_enum'.ljust(15), timeit.timeit('t3_enum(1048575)', 'from __main__ import t3_enum', number=100000))
        print('gbriones_gdl'.ljust(15), timeit.timeit('gbriones_gdl(1048575)', 'from __main__ import gbriones_gdl', number=100000))
        print('t3_gen'.ljust(15), timeit.timeit('t3_gen(1048575)', 'from __main__ import t3_gen', number=100000))
        print('\nnullptr:\n===========================')
        print(dis.dis(nullptr))
        print('\nmoose:\n===========================')
        print(dis.dis(moose))
        print('\nt3_enum:\n===========================')
        print(dis.dis(t3_gen))
        print('gbriones_gdl:\n===========================')
        print(dis.dis(t3_enum))
        print('\nt3_gen:\n===========================')
        print(dis.dis(gbriones_gdl))
        

        结果如下:

        Each function gives correct results: True
        
        nullptr         0.7847449885390462
        moose           1.810839785503465
        t3_enum         2.898256901365956
        gbriones_gdl    3.0904670146624778
        t3_gen          21.366890624367063
        
        nullptr:
        ===========================
         14           0 BUILD_LIST               0
                      3 STORE_FAST               1 (powers)
        
         15           6 LOAD_CONST               1 (1)
                      9 STORE_FAST               2 (i)
        
         16          12 SETUP_LOOP              52 (to 67)
                >>   15 LOAD_FAST                2 (i)
                     18 LOAD_FAST                0 (num)
                     21 COMPARE_OP               1 (<=)
                     24 POP_JUMP_IF_FALSE       66
        
         17          27 LOAD_FAST                2 (i)
                     30 LOAD_FAST                0 (num)
                     33 BINARY_AND
                     34 POP_JUMP_IF_FALSE       53
        
         18          37 LOAD_FAST                1 (powers)
                     40 LOAD_ATTR                0 (append)
                     43 LOAD_FAST                2 (i)
                     46 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     49 POP_TOP
                     50 JUMP_FORWARD             0 (to 53)
        
         19     >>   53 LOAD_FAST                2 (i)
                     56 LOAD_CONST               1 (1)
                     59 INPLACE_LSHIFT
                     60 STORE_FAST               2 (i)
                     63 JUMP_ABSOLUTE           15
                >>   66 POP_BLOCK
        
         20     >>   67 LOAD_FAST                1 (powers)
                     70 RETURN_VALUE
        None
        
        moose:
        ===========================
         44           0 LOAD_CONST               1 (<code object <lambda> at 0x0000000002A8E660, file "power_2_adder.py", line 44>)
                      3 LOAD_CONST               2 ('moose.<locals>.<lambda>')
                      6 MAKE_FUNCTION            0
                      9 STORE_FAST               1 (get_bin)
        
         45          12 LOAD_FAST                1 (get_bin)
                     15 LOAD_FAST                0 (num)
                     18 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     21 STORE_FAST               2 (bin_str)
        
         46          24 BUILD_LIST               0
                     27 STORE_FAST               3 (powers)
        
         47          30 SETUP_LOOP              71 (to 104)
                     33 LOAD_GLOBAL              0 (enumerate)
                     36 LOAD_FAST                2 (bin_str)
                     39 LOAD_CONST               0 (None)
                     42 LOAD_CONST               0 (None)
                     45 LOAD_CONST               6 (-1)
                     48 BUILD_SLICE              3
                     51 BINARY_SUBSCR
                     52 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     55 GET_ITER
                >>   56 FOR_ITER                44 (to 103)
                     59 UNPACK_SEQUENCE          2
                     62 STORE_FAST               4 (i)
                     65 STORE_FAST               5 (digit)
        
         48          68 LOAD_FAST                5 (digit)
                     71 LOAD_CONST               4 ('1')
                     74 COMPARE_OP               2 (==)
                     77 POP_JUMP_IF_FALSE       56
        
         49          80 LOAD_FAST                3 (powers)
                     83 LOAD_ATTR                1 (append)
                     86 LOAD_CONST               5 (2)
                     89 LOAD_FAST                4 (i)
                     92 BINARY_POWER
                     93 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     96 POP_TOP
                     97 JUMP_ABSOLUTE           56
                    100 JUMP_ABSOLUTE           56
                >>  103 POP_BLOCK
        
         50     >>  104 LOAD_FAST                3 (powers)
                    107 RETURN_VALUE
        None
        
        t3_enum:
        ===========================
         23           0 BUILD_LIST               0
                      3 STORE_FAST               1 (d)
        
         24           6 SETUP_LOOP             101 (to 110)
                >>    9 LOAD_GLOBAL              0 (sum)
                     12 LOAD_FAST                1 (d)
                     15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     18 LOAD_FAST                0 (num)
                     21 COMPARE_OP               0 (<)
                     24 POP_JUMP_IF_FALSE      109
        
         25          27 LOAD_GLOBAL              1 (powers_of_2)
                     30 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
                     33 STORE_FAST               2 (p)
        
         26          36 LOAD_CONST               1 (1)
                     39 DUP_TOP
                     40 STORE_FAST               3 (a)
                     43 STORE_FAST               4 (b)
        
         27          46 SETUP_LOOP              44 (to 93)
                >>   49 LOAD_GLOBAL              0 (sum)
                     52 LOAD_FAST                1 (d)
                     55 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     58 LOAD_FAST                3 (a)
                     61 BINARY_ADD
                     62 LOAD_FAST                0 (num)
                     65 COMPARE_OP               1 (<=)
                     68 POP_JUMP_IF_FALSE       92
        
         28          71 LOAD_FAST                3 (a)
                     74 STORE_FAST               4 (b)
        
         29          77 LOAD_GLOBAL              2 (next)
                     80 LOAD_FAST                2 (p)
                     83 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     86 STORE_FAST               3 (a)
                     89 JUMP_ABSOLUTE           49
                >>   92 POP_BLOCK
        
         30     >>   93 LOAD_FAST                1 (d)
                     96 LOAD_ATTR                3 (append)
                     99 LOAD_FAST                4 (b)
                    102 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                    105 POP_TOP
                    106 JUMP_ABSOLUTE            9
                >>  109 POP_BLOCK
        
         31     >>  110 LOAD_FAST                1 (d)
                    113 LOAD_ATTR                4 (reverse)
                    116 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
                    119 POP_TOP
        
         32         120 LOAD_FAST                1 (d)
                    123 RETURN_VALUE
        None
        gbriones_gdl:
        ===========================
         41           0 LOAD_CONST               1 (<code object <listcomp> at 0x0000000002A8E540, file "power_2_adder.py", line 41>)
                      3 LOAD_CONST               2 ('t3_enum.<locals>.<listcomp>')
                      6 MAKE_FUNCTION            0
                      9 LOAD_GLOBAL              0 (enumerate)
                     12 LOAD_GLOBAL              1 (bin)
                     15 LOAD_FAST                0 (num)
                     18 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     21 LOAD_CONST               0 (None)
                     24 LOAD_CONST               3 (1)
                     27 LOAD_CONST               4 (-1)
                     30 BUILD_SLICE              3
                     33 BINARY_SUBSCR
                     34 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     37 GET_ITER
                     38 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     41 RETURN_VALUE
        None
        
        t3_gen:
        ===========================
          6           0 BUILD_LIST               0
                      3 STORE_FAST               1 (result)
        
          7           6 LOAD_GLOBAL              0 (bin)
                      9 LOAD_FAST                0 (num)
                     12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     15 LOAD_CONST               0 (None)
                     18 LOAD_CONST               1 (1)
                     21 LOAD_CONST               3 (-1)
                     24 BUILD_SLICE              3
                     27 BINARY_SUBSCR
                     28 STORE_FAST               2 (binary)
        
          8          31 SETUP_LOOP              62 (to 96)
                     34 LOAD_GLOBAL              1 (range)
                     37 LOAD_GLOBAL              2 (len)
                     40 LOAD_FAST                2 (binary)
                     43 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     46 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     49 GET_ITER
                >>   50 FOR_ITER                42 (to 95)
                     53 STORE_FAST               3 (x)
        
          9          56 LOAD_GLOBAL              3 (int)
                     59 LOAD_FAST                2 (binary)
                     62 LOAD_FAST                3 (x)
                     65 BINARY_SUBSCR
                     66 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     69 POP_JUMP_IF_FALSE       50
        
         10          72 LOAD_FAST                1 (result)
                     75 LOAD_ATTR                4 (append)
                     78 LOAD_CONST               2 (2)
                     81 LOAD_FAST                3 (x)
                     84 BINARY_POWER
                     85 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                     88 POP_TOP
                     89 JUMP_ABSOLUTE           50
                     92 JUMP_ABSOLUTE           50
                >>   95 POP_BLOCK
        
         11     >>   96 LOAD_FAST                1 (result)
                     99 RETURN_VALUE
        None
        

        timeit 的结果中,我们可以看到@nullptr 的解决方案非常好,正如我所怀疑的那样,其次是@moose 的解决方案。在那之后,我结合了@moose 和@gbriones.gdl 的解决方案,紧随其后的是@gbriones.gdl 的解决方案。容我们说,我的生成器解决方案非常不理想,但我有点预料到。

        dis 结果包含在内以确保完整性。

        【讨论】:

        【解决方案7】:

        这个想法是将数字转换为二进制,然后从二进制表示中获得 2 的幂:

        #!/usr/bin/env python
        
        
        def get_powers(n):
            """Get positive powers of two which add up to n.
        
            Parameters
            ----------
            n : positive integer
        
            Returns
            -------
            list of integers which are powers of 2
        
            Examples
            --------
            >>> get_powers(14)
            [2, 4, 8]
        
            >>> get_powers(5)
            [1, 4]
            """
            get_bin = lambda x: x >= 0 and str(bin(x))[2:] or "-" + str(bin(x))[3:]
            bin_str = get_bin(n)  # convert n to a binary string
            powers = []
            for i, digit in enumerate(bin_str[::-1]):
                if digit == '1':
                    powers.append(2**i)
            return powers
        

        【讨论】:

          【解决方案8】:

          与其解决问题,不如提供一些信息来帮助您解决问题?看几个例子,然后解决它们。这里有一些,

          假设 N=2,那么答案是 = {2=2^1}。

          假设N=3,那么答案是= {2=2^1,1=2^0}(注意2**0=1)

          假设 N=4,那么答案是 = {4=2^2}

          ...

          假设 N=63,那么答案是 = {32=2^5, 16=2^4, 8=2^3, 4=2^2, 2=2^1, 1=2^0}

          假设 N=64,那么答案是 = {64=2^6}

          ...

          假设 N=259,那么答案是 = {256=2^8, 2=2^1, 1=2^0}

          你看到模式了吗?


          想要算法吗?

          想想这些简单的步骤,然后将它们组合成一个循环,

          你能检查数字是否是奇数吗?当数字为奇数时,您检测到有点“开”。减一(使数字变为偶数)。

          你能除以 2 吗?你如何处理结果?

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-16
            • 2015-11-17
            • 1970-01-01
            相关资源
            最近更新 更多