【问题标题】:Minimum bit length needed for a positive integer in PythonPython中正整数的位长
【发布时间】:2011-02-08 21:29:28
【问题描述】:
1 = 0b1 -> 1
5 = 0b101 -> 3
10 = 0b1010 -> 4
100 = 0b1100100 -> 7
1000 = 0b1111101000 -> 10
…

如何获取整数的位长,即在 Python 中表示正整数所需的位数?

【问题讨论】:

    标签: python bits bitcount


    【解决方案1】:

    在 python 2.7+ 中有一个int.bit_length() 方法:

    >>> a = 100
    >>> a.bit_length()
    7
    

    【讨论】:

    • 奇怪的是,你不能在整数文字上调用bit_length()
    • @EricWalker 当然可以。您可以在任何拥有它的对象上调用方法。文字也不例外。您确实需要使用正确的语法:如果您编写 2.,它是一个浮点字面量,而不是后跟字段访问运算符的整数字面量。放一个空格2 .bit_length() 或使用括号(2).bit_length()
    • @Gilles'SO-stopbeingevil' 感谢您提供有用的澄清。
    • 你也可以在 python 3 中使用 bit_length() 方法!
    【解决方案2】:
    >>> len(bin(1000))-2
    10
    >>> len(bin(100))-2
    7
    >>> len(bin(10))-2
    4
    

    注意:不适用于负数,可能需要减去 3 而不是 2

    【讨论】:

    • 这不适用于负数(虽然它也不会失败,与日志版本相反)
    • 如果你关心负数,请len(bin(abs(n)))-2
    • 更重要的是,0 失败。
    • 另一种方法是使用len("{:b}".format(x)) 来避免减法。
    • 根据 Python 文档,bin(n).lstrip('-0b') 适用于负数,相当于bit_length
    【解决方案3】:

    如果您的 Python 版本有它(Python 2 ≥2.7,Python 3 ≥3.1),请使用标准库中的 bit_length 方法。

    否则,len(bin(n))-2 as suggested by YOU 很快(因为它是用 Python 实现的)。请注意,这会为 0 返回 1。

    否则,一个简单的方法是重复除以 2(这是一个简单的位移),并计算达到 0 需要多长时间。

    def bit_length(n): # return the bit size of a non-negative integer
        bits = 0
        while n >> bits: bits += 1
        return bits
    

    一次移动整个单词,然后返回并处理最后一个单词的位,速度要快得多(至少对于大数字而言——快速基准测试表明 1000 位的速度要快 10 倍以上)。

    def bit_length(n): # return the bit size of a non-negative integer
        if n == 0: return 0
        bits = -32
        m = 0
        while n:
            m = n
            n >>= 32; bits += 32
        while m: m >>= 1; bits += 1
        return bits
    

    在我的快速基准测试中,len(bin(n)) 的运行速度明显快于单词大小的块版本。尽管bin(n) 构建了一个立即丢弃的字符串,但由于有一个编译为机器代码的内部循环,它会出现在最前面。 (math.log 甚至更快,但这并不重要,因为它是错误的。)

    【讨论】:

    • @JonathanEunice 您在谈论哪个实现,为什么您认为它不正确? 5的位长为3。
    • 我的错!我误读了这个问题(作为“N中设置的位数”而不是“代表N的位数”)。我撤回批评。
    • 我也是这么想的 :P,不过很高兴知道 bit_length
    • 对于那些看到上述 cmets 的人来说,一个数字中升高的位数的术语称为 population count,通常缩写为 popcount .此解决方案不是如何找到 popcount - 请参阅here 了解如何在 Python 中执行 popcount。
    【解决方案4】:

    这里我们也可以使用切片。

    对于正整数,我们从 2 开始:

    len(bin(1)[2:])
    len(bin(5)[2:])
    len(bin(10)[2:])
    len(bin(100)[2:])
    len(bin(1000)[2:])
    

    将打印:

    1
    3
    4
    7
    10
    

    对于负整数,我们从 3 开始:

    len(bin(-1)[3:])
    len(bin(-5)[3:])
    len(bin(-10)[3:])
    len(bin(-100)[3:])
    len(bin(-1000)[3:])
    

    将打印:

    1
    3
    4
    7
    10
    

    【讨论】:

      【解决方案5】:

      这是另一种方式:

      def number_of_bits(n):
          return len('{:b}'.format(n))
      

      我想效率不高,但没有出现在之前的任何答案中......

      【讨论】:

        【解决方案6】:
        def bitcounter(n):
            return math.floor(math.log(n,2)) + 1
        

        EDIT 已修复,以便与 1 一起使用

        【讨论】:

        • 这是 2 的幂次方。
        • @Ants Aasma:你确定吗?假设 math.log(n, 2) 给出完全正确的结果,对我来说看起来不错。
        • @MarkDickinson: math.log(n, 2) 没有给出完全正确的结果。例如math.log(2**29, 2) = 29.000000000000004。
        • @endolith:是的;我正在挠头,试图弄清楚当我写那条评论时我到底在想什么。 FWIW,Python 3 有 math.log2,它确实给出了 2 的精确幂的浮点数的精确结果。
        • @endolith:虽然有趣的是,在我的机器上,我得到了所有非负的nlog(2**n, 2) >= n,所以math.floor(math.log(n, 2)) + 1 仍然给出了 2 的幂的正确结果。虽然不是,当然,对于所有nn = 2**48 - 1 似乎是它失败的最小值。
        【解决方案7】:

        此解决方案利用 .bit_length()(如果可用),而对于旧版本的 Python,则回退到 len(hex(a))。它比bin 的优势在于它创建了一个更小的临时字符串,因此它使用更少的内存。

        请注意,它返回 1 对 0,但这很容易更改。

        _HEX_BIT_COUNT_MAP = {
            '0': 0, '1': 1, '2': 2, '3': 2, '4': 3, '5': 3, '6': 3, '7': 3}
        
        def bit_count(a):
          """Returns the number of bits needed to represent abs(a). Returns 1 for 0."""
          if not isinstance(a, (int, long)):
            raise TypeError
          if not a:
            return 1
          # Example: hex(-0xabc) == '-0xabc'. 'L' is appended for longs.
          s = hex(a)
          d = len(s)
          if s[-1] == 'L':
            d -= 1
          if s[0] == '-':
            d -= 4
            c = s[3]
          else:
            d -= 3
            c = s[2]
          return _HEX_BIT_COUNT_MAP.get(c, 4) + (d << 2)
        
        
        # Use int.bit_length and long.bit_length introduced in Python 2.7 and 3.x.
        if getattr(0, 'bit_length', None):
          __doc = bit_count.__doc__
          def bit_count(a):
            return a.bit_length() or 1
          bit_count.__doc__ = __doc
        
        assert bit_count(0) == 1
        assert bit_count(1) == 1
        assert bit_count(2) == 2
        assert bit_count(3) == 2
        assert bit_count(63) == 6
        assert bit_count(64) == 7
        assert bit_count(75) == 7
        assert bit_count(2047) == 11
        assert bit_count(2048) == 12
        assert bit_count(-4007) == 12
        assert bit_count(4095) == 12
        assert bit_count(4096) == 13
        assert bit_count(1 << 1203) == 1204
        assert bit_count(-(1 << 1203)) == 1204
        assert bit_count(1 << 1204) == 1205
        assert bit_count(1 << 1205) == 1206
        assert bit_count(1 << 1206) == 1207
        

        【讨论】:

        • 而不是检查它是否有bit_length,你应该尝试使用它然后except AttributeError?
        • @endolith:对这段代码有很大的改进吗?以什么方式?
        • 如果您期望 bit_length 可用,它会更有效
        • @endolith:你确定它更有效率吗? (您是否对其进行了基准测试?)在这种情况下差异是否显着?
        • @pts 处理 AttributeError 被认为更 Pythonic。例如,stackoverflow.com/a/12265860/687467
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        • 2020-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多