【问题标题】:Pythonic way to count the number of trailing zeros in base 2Pythonic方法来计算以2为底的尾随零的数量
【发布时间】:2020-08-24 05:30:29
【问题描述】:

我正在寻找一种 Pythonic 方法来计算正整数 n 的二进制表示中尾随零的数量(这将表示 2 的最高幂,它除以 n 没有余数)。

一个简单的解决方案:

def CountZeros(n):
    c = 0
    while (n % 2) == 0:
        n /= 2
        c += 1
    return c

但是为了以更 Pythonic 的方式来做,我认为我可以利用:

  • bin(n)[2:],它给出了n 的二进制表示
  • bin(n)[:1:-1],它给出了 n 的反向二进制表示

所以我的问题可以简化为计算字符串中尾随零的数量。

有没有单语句的方式来做到这一点?

我的最终目标是用 Pythonic 方法计算 2 的最高幂,它除以 n 而没有余数,因此任何不通过计算字符串中的尾随零来实现这一点的方法也值得赞赏。

【问题讨论】:

  • 比较字符串的长度和带零的字符串的长度stripped?或者也许有一个数学解决方案。
  • 所谓的重复似乎是关于计数十进制零(问题并不明确,但所有答案都假设十进制零是什么意思),而这个是关于二进制零。投票重新开放。
  • 在 Python 3 中,对于积极的 n,您可以执行 (n ^ (n-1)).bit_length()-1,尽管对于 n=0,这将评估为 0。如果你想让n=0给1,那么你可以做((n ^ (n-1))>>1).bit_length()
  • @TigerhawkT3,你能重新打开这个问题,以便可以发布 PM-2Ring 的比特旋转解决方案作为答案吗?另一个问题是关于十进制零,所以它不是重复的,这个答案在那里不起作用。

标签: python


【解决方案1】:

你可以使用str.rstrip:

def trailing(s):
    return len(s) - len(s.rstrip('0'))

【讨论】:

  • 谢谢!任何 Pythonic 方式来实现我的实际目的(计算 2 的最高幂,它除以 n 而没有余数),也许是直接处理整数值而不是它的字符串表示?
  • @barakmanos - 将一个变量初始化为 2,开始一个无限循环,将您的数字除以该变量,如果没有余数则保存该变量,如果它大于您的数字,则返回该变量,乘以该变量2.
  • 是的,这就是我的问题中的编码示例,以防您没有注意到...无论如何谢谢...
【解决方案2】:

避免使用bin 转换为字符串,而不是使用修改后的bithack,速度提高了一倍,因为我们已经有了一个高效的log2 实现。

def ctz(v):
    return (v & -v).bit_length() - 1

如果输入为 0,上述返回 -1。

使用 C 使其速度再次提高一倍:

from gmpy2 import bit_scan1 as ctz

如果输入为零,此版本返回 None。


例如,如果输入为 20,则考虑无限二进制展开:

v    000...00010100
~v   111...11101011 (not used directly, all bits opposite)
-v   111...11101100 (-v == ~v + 1; this causes all low 1 bits to overflow and carry)
v&-v 000...00000100 (has a single 1 bit, from the carry)

当是anded 时,所有前导零和一位都是相反的,但最后一位和所有尾随零都是相同的。

然后.bit_length() 告诉我们整数总共使用 3 位,因此只需减去 1 即可仅考虑零。

【讨论】:

    【解决方案3】:

    这可能会。

    def trailing_zeros(n):
        s = str(n)
        return len(s)-len(s.rstrip('0'))
    

    【讨论】:

      【解决方案4】:

      我不确定这是否是最快的解决方案,但它对我来说似乎是最合乎逻辑的:

      def trailing_zeros(n):
          for i in range(20):
              if n % (2<<i) != 0:
                  return i
      

      既然你要的是单行语句,这里就一个,但我觉得不是很清晰(而且效率比另一个差):

      max(i+1 for i in range(20) if n%(2<<i) == 0)
      

      【讨论】:

      • 它做得很好,但如果数字之间有一个零,它会失败 1。对于1000200,它返回 3。
      • @ssj.luffy 因为100200 在二进制中应该是11110100001100001000。
      • 哦,我错过了问题的binary representation 部分。根据提供的代码 OP,我认为他需要数字本身的尾随零。好东西。 +1
      【解决方案5】:

      如果您特别关注数字的底层二进制表示,请务必使用位推送操作。除法和模除法是最昂贵的操作,并且与算术而不是硬件位有关。所以(未经测试的代码)

      def fnzb( n):
          " return position of first non-zero bit in n"
          if n==0:
              # edge case, there ARE no nonzero bits
              return None
          for po2 in range(0, 128) # or whatever larger upper limit is desired
              if a & ( 1 << po2) != 0: return po2
          # edge case, n too large
          raise ValueError,  "'impossibly' large integer argument encountered"
      

      如果这些整数可能通常非常大且带有很多尾随零(对于“大”的加密值),它可能对初始化test=1 并右移它的效率产生重要影响每次环游一个地方,而不是从 1 开始并移动它po2 个地方。

      【讨论】:

        猜你喜欢
        • 2018-11-06
        • 1970-01-01
        • 1970-01-01
        • 2015-11-11
        • 1970-01-01
        • 1970-01-01
        • 2014-05-26
        • 2017-07-12
        • 2014-01-11
        相关资源
        最近更新 更多