【问题标题】:logical right shift in python - meaning of the expression (num % 0x100000000) >> 1python中的逻辑右移-表达式的含义(num % 0x100000000)>> 1
【发布时间】:2020-09-29 23:48:11
【问题描述】:

在 java 中,我们有 '>>>' 用于逻辑右移操作,这在 Python 中是缺失的。 我遇到过这种表达方式:

(num % 0x100000000) >> 1

我正在尝试理解它是如何工作的并理解它,这样我就不必去死记硬背了。

谢谢

【问题讨论】:

    标签: python bit-manipulation logical-operators


    【解决方案1】:

    该表达式与逻辑移位和算术移位之间的区别几乎没有关系,后者保留符号(当您谈论二进制补码时,最左边的位)。

    在您问题的表达式中,num % 0x100000000 只是去掉最右边 32 位左侧的任何内容,以确保您要移动的值被强制转换为 32 位范围0 - 0xffffffff。然后>> 1 向右移动。因为你已经强制了范围,所以即使你的输入值是像 0xffffffff12345678 这样的奇怪的东西,你也可以保证得到一个 0 移动到最左边的位。

    【讨论】:

      【解决方案2】:

      首先,Python 确实有>>,但没有像>>> 这样的三元运算符。 >> 进行按位右移:

      https://wiki.python.org/moin/BitwiseOperators

      Java 中的>>> 运算符将位右移“无符号”,这意味着最新的最左侧位始终是0 位。 (“有符号”移位会复制符号位,因此对于正整数值会有一个 0 位,对于负整数值会有一个 1 位。)

      Java 有一个特定大小的变量的概念:你可以有一个 32 位整数或 64 位整数等。在 Python 中,我们只有 int 类型的对象,它们是任意精度的(它们根据需要具有尽可能多的存储位,因此可以存储非常大的值)。因此,在您的代码 sn-p 中,我们的第一步是确保我们的整数值最大为 32 位。

      我不知道你在哪里找到了这个例子,但它混合了模数运算和位移。常数0x1000000002**32。 Modulus 求除法后的余数。所以这个模运算将只保留整数值的最低 32 位。

      就我个人而言,我会使用逻辑 AND 来执行该操作:

      x & 0xff_ff_ff_ff(请注意,下划线在 Python 3.x 中是合法的“糖”;它们不做任何事情,但我们可以使用它们来分隔数字组。在这种情况下,我使用它们来分隔字节,以明确表示这是四个0xff 字节串在一起组成2**32 - 1

      此断言不会在我的计算机上触发,因为这两个值相等: assert x & 0xff_ff_ff_ff == x % 0x100000000

      但是模运算符有一个优点:无论您在“大端”计算机还是“小端”计算机上运行该代码,它都应该提供数字的低位。我使用的是 AMD 64 位处理器,即 x86,这意味着它是 little-endian。 (我实际上不确定在大端系统上的 Python 中按位与如何工作;我对大端系统上的 C 有一些经验,但在 Python 上没有。它可能真的有效!但模数肯定会工作。 )

      因此,在隔离了值的低 32 位之后,我们想要右移 1 位。我们总是需要注意运算符的优先级,以确保事情以正确的顺序发生;在这种情况下,显式括号保证移位发生在我们只取最低 32 位之后。

      当模数抓取低 32 位时,结果永远不会是负数:它将是从 00xff_ff_ff_ff 范围内的整数。因此,当右移高位时,肯定是0 位。因此,这段代码 sn-p 保证产生与将整数值放入 Java 32 位整数变量然后使用 >>> 右移相同的结果。

      【讨论】:

      • 计算机的字节顺序或 Python 实现在这里无关紧要。这是内部的,当您只是将数字用作数字时没有任何区别。顺便说一句,我会写 % 2**32 ,更容易写和读。
      • @superbrain 我尽量小心处理字节序问题。由于我现在还没有准备好在大端系统上测试行为,所以我只是说我不确定。我认为你可能是对的,这实际上并不重要。
      • 您在谈论0xff_ff_ff_ff 时谈论字节的方式听起来您可能正在考虑比实际更低的水平。那不是四个字节,它只是一个用十六进制写的整数文字。 内部甚至不会产生四个 0xff 字节,因为 Python 使用 30 位数字。如果您使用例如int.to_bytesint.from_bytes,您只会处理字节,但是您指定了字节顺序,例如(1234).to_bytes(2, 'big')& 操作对两个整数进行操作。不管它们内部是大端还是小端,它们都会使用相同的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多