【问题标题】:How to get the logical right binary shift in python如何在python中获得逻辑正确的二进制移位
【发布时间】:2011-04-29 13:55:41
【问题描述】:

正如标题所示,在 JavaScript 中有一个特定的运算符 >>>。例如,在 JavaScript 中我们会得到以下结果:

(-1000) >>> 3 = 536870787

(-1000) >> 3 = -125

1000 >>> 3 = 125

1000 >> 3 = 125

那么是否有某种方法或运算符代表这个>>>

【问题讨论】:

    标签: python bitwise-operators


    【解决方案1】:

    对此没有内置运算符,但您可以自己轻松模拟>>>

    >>> def rshift(val, n): return val>>n if val >= 0 else (val+0x100000000)>>n
    ... 
    >>> rshift(-1000, 3)
    536870787
    >>> rshift(1000, 3)
    125
    

    以下替代实现无需if

    >>> def rshift(val, n): return (val % 0x100000000) >> n
    

    【讨论】:

    • (val + 0x100000000) % 0x100000000)val % 0x100000000
    • @Baffe Boyois:在 Python 中肯定不是(结果总是正数,而第一个操作数可以有任何一个符号)。
    • 0x100000000 是1 << 32,32 是用于表示整数的位数(这很重要,但在任何地方都没有说明)。如果您有 64 位整数,则必须改用 1 << 64
    • 如果 val
    【解决方案2】:

    不,没有。 python中的右移是算术的。

    【讨论】:

    • 那么这是否包含在某些包中?
    • 由于 Python 没有无符号数,所以它不包含无符号移位才有意义。
    • @Mark Ransom:错了,您可能需要计算用另一种语言定义的表达式(就像我现在所做的那样)。但我同意,由于不存在无符号数字,因此对无符号移位的需求相当有限。
    【解决方案3】:

    这是aix's answer 的衍生产品。如果你给它一个正值,正常的右移运算符将起作用,所以你真的在寻找从有符号到无符号的转换。

    def unsigned32(signed):
        return signed % 0x100000000
    
    >>> unsigned32(-1000) >> 3
    536870787L
    

    【讨论】:

      【解决方案4】:

      Numpy 提供了执行此操作的 right_shift() 函数:

      >>> import numpy
      >>> numpy.right_shift(1000, 3)
      125
      

      【讨论】:

      • 但这不只是>> 运算符吗?如果我尝试numpy.right_shift(-1000, 3) 我会得到-125 而不是536870787
      • @ScottGriffiths 是对的。但是,您可以使用 numpy 将其转换为无符号类型,然后使用普通运算符,例如:numpy.uint32(-1000) >> 3。请注意,我测试此特定案例时的输出类型是 numpy.int64(已签名)。
      【解决方案5】:

      您可以使用 bitstring 模块使用 >>= 运算符使用零进行按位移位填充:

      >>> a = BitArray(int=-1000, length=32)
      >>> a.int
      -1000
      >>> a >>= 3
      >>> a.int
      536870787
      

      【讨论】:

      • 旋转与移位不同。
      • @Mark:公平点——我误解了 >>> 操作员在做什么。现已修复。
      【解决方案6】:

      试图通过用 0x100000000 屏蔽负数来翻转负数的符号位从根本上是错误的,因为它对字长做出了严格的假设。在我作为程序员的时候,我使用过 24、48、16、18、32、36 和 64 位数字。我还听说过在奇数长度上工作的机器,例如 37 和其他使用补码而不是补码算术的机器。你对数字的内部表示所做的任何假设,除了它们是二进制的,都是危险的。

      即使是二元假设也不是绝对安全的,但我认为我们会允许这样做。 :)

      【讨论】:

        【解决方案7】:

        您需要记住,如果数字为负数,则设置最高位,并且每次右移时,您还需要设置最高位。

        这是我的实现:

        def rshift(val, n):
            s = val & 0x80000000
            for i in range(0,n):
                val >>= 1
                val |= s
            return val
        

        【讨论】:

        • 我认为您对问题的理解是倒退的。所有 python 移位都是算术的。您已经实现了算术移位。,复制了 python 的功能最初的问题是要求逻辑移位运算符,而不是算术移位。
        【解决方案8】:

        无需模数的解决方案:

        >>> def rshift(val,n): return (val>>n) & (0x7fffffff>>(n-1))

        这是有效的,因为 7fffffff 是一个正数,并且右移会在左边添加零。

        【讨论】:

          【解决方案9】:

          你也可以使用楼层划分:

          def rshift(val, n):
              if val > 0:
                  return val >> n
              return val // -(2^n)
          

          【讨论】:

            【解决方案10】:

            这不是一种有效的方法,但可以按预期工作

            def _toBinary(x):
                x=int(x)
                binary = []
                while x > 0:
                    binary.append(str(x%2))
                    x=int(x/2)
                return "".join(binary[::-1])
            
            def _fromBinary(xs):
                ans = 0
                for i,x in enumerate(xs[::-1]):
                    if x == '1':
                        ans += 2**i
                return ans
            
            def leftLogicalShift(x,n=1):
                if not type(x) == int:
                    return x
                xs = _toBinary(x)
                xs = [x for x in xs]
                for _ in range(n):
                    xs.pop(0)
                    xs.append('0')
                return _fromBinary("".join(xs))
            
            def rightLogicalShift(x,n=1):
                if not type(x) == int:
                    return x
                xs = _toBinary(x)
                xs = [x for x in xs]
                for _ in range(n):
                    xs.pop()
                    xs.insert(0,'0')
                return _fromBinary("".join(xs))
            
            def leftArithmeticShift(x,n=1):
                return leftLogicalShift(x,n)
            
            def rightArithmeticShift(x,n=1):
                if not type(x) == int:
                    return x
                xs = _toBinary(x)
                xs = [x for x in xs]
                for _ in range(n):
                    tmp = xs[0]
                    xs.pop()
                    xs.insert(0,tmp)
                return _fromBinary("".join(xs))
            
            lls = leftLogicalShift(10,2) 
            print(lls) # 8
            
            rls = rightLogicalShift(10,2) 
            print(rls) # 2
            
            las = leftArithmeticShift(10,2)
            print(las) # 8
            
            ras = rightArithmeticShift(10,2)
            print(ras) # 14
            

            参考:

            https://open4tech.com/logical-vs-arithmetic-shift/

            https://www.interviewcake.com/concept/java/bit-shift

            【讨论】:

              【解决方案11】:

              我认为 逻辑右二进制移位 在 Python 中不直接可用。相反,您可以在 Python 中使用 Javascript,如下所示:

              import js2py
              rshift = js2py.eval_js('function $(a, b){ return a >>> b}')
              print (rshift(244, 324)) #15
              

              【讨论】:

                【解决方案12】:

                投票最多的答案在 val

                def rshift(val, n):
                    if (val >= 0): return val >> n
                    elif (n == 0): return val
                    else: return (val + 0x10000000) >> n
                
                >>> rshift(-1, 0)
                -1
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-07-18
                  • 2018-05-28
                  • 1970-01-01
                  • 2019-12-14
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-09-09
                  • 2020-09-09
                  相关资源
                  最近更新 更多