【问题标题】:How to think about Python's negative number bitwise operations?如何思考 Python 的负数按位运算?
【发布时间】:2020-03-07 09:14:30
【问题描述】:

我发现很难考虑 Python(和 Python3)的无限精度负数和按位运算。它不是 32 位或 64 位的。左边的1s 可以认为是“无限多”。它不是很确定,这就是为什么有时很难考虑它是如何工作的。

似乎一种可行的方法是:总是做得更多,例如,如果您正在处理具有 67 位的正整数,那么只需将它们与负数的运算视为具有 96 位或 128 位-少量。这是一个正确的思考方式吗?规范中有什么说明它是如何工作的或应该考虑的吗? (比如内部实现只考虑正整数,只考虑负数为“左多1位”?)

【问题讨论】:

  • 好吧,你有没有试过把你的想法编码并检查它在现实中是如何运作的?
  • 我有……但我没有看到一个非常明确的规则……我觉得我有时只能猜测
  • 所以粘贴你的代码。
  • “规范中有什么说明它是如何工作或应该考虑的吗?” - 有,and it says exactly what you don't want to hear:“按位运算的结果被计算为好像用无限数量的符号位在二进制补码中执行一样。”
  • 我认为您应该将此视为一个习惯于思考无穷大的机会。这不是他们唯一一次出现。该技能将很有用。

标签: python python-3.x bit-manipulation negative-number


【解决方案1】:

您应该将它们视为具有无限多个 1 位。在摘要中,two's complement 二进制表示无限多个 1;并不是说可以根据需要添加更多的 1,而是那些 1已经是数字表示方式的一部分。

那些无限多的位实际上并未存储在内存中这一事实是一个实现细节,因此当您考虑这一点时,您应该忽略内存的限制,直到您遇到您 em> 是必须编写实现的人。如果您只是想从概念上理解这一点,则无需考虑后备位之类的事情,而且我认为这不一定有帮助。


二进制数表示2的幂的和,例如:

110012 = 24 + 23 + 0 + 0 + 20

数字-1由1的无限序列表示,向左无限延伸:

...11112 = ... + 23 + 22 + 21 + 20

这在通常意义上的无限级数中是无稽之谈,但有充分的理由将结果定义为 -1。最直观吸引人的原因是,当您按照加法算法向其添加 1 时会发生什么:

  ...111111111
+            1
  ――――――――――――
= ...000000000 (result)
  ――――――――――――
  ...11111111  (carry)

在最右边的列中,您有 1 + 1,即 2,或二进制的 102,因此您写入 0 并将 1 带到左侧的下一列。然后在该列中你有一个 1 加上携带的 1,所以你写 0 并携带另一个 1...等等,ad infinitum。结果在每个位置都有一个 0。因此,...111112 一定代表了 -1,因为我们按照算法加 1,得到了 0 的表示。

如果这还不够令人满意,那么还有其他原因应该将 ...111112 解释为 -1 的表示:

  • 无穷和 1 + 2 + 4 + 8 + ... 是一个几何级数;具有恒定比率 r 的几何级数的公式是 1/(1 - r)。这个公式只适用于 -1 
  • 无限和 1 + 2 + 4 + 8 + ... 实际上确实2-adic norm 中收敛到 -1。
  • 结果 -1 也可以通过其他定义获得,包括 Euler summationas noted by Wikipedia 任何同时稳定线性的求和方法将这个总和关联起来结果为 ∞ 或 -1。

我提到这些也是因为它们暗示某些属性仍然适用于算术;将常用的加法、减法和乘法算法应用到“无穷大”可以得到符合算术通常属性的合理结果,如结合性、交换性和分布性。

【讨论】:

    【解决方案2】:

    无限精度的实现方法有很多,但你应该在这里提出你的实际情况才能得到答案。

    我也不认为你不理解左边无限多个 1 的概念。 正整数:将未保存的位回退到 0,从最低意义保存所有 1 位 负整数:将未保存的位回退到 1,从最低意义保存所有 0 位

    当您需要对 2 个无限精度的位进行逐位运算时,您也只需对后备位进行操作即可。 示例:

    -25 ^ -1029
    -25 = -1 - 8 - 16: 11100(+infinitely many unsaved 1's beyond these 5 saved bits)
    -1029 = -1 - 4 - 1024: 11011111110(+infinitely many unsaved 1's beyond these 11 saved bits)
    Take XOR, you have to fill more 1's to align the longer one. So it is:
    11100111111(+infinitely many unsaved 1's beyond this)
    ^
    11011111110(+infinitely many unsaved 1's beyond this)
    =
    00111000001(+infinitely many unsaved 0's beyond this)
    = 4 + 8 + 16 + 1024 = 1052
    

    根据您的问题,我认为您并不真正需要有关 Python 如何实现此功能的技术细节......

    【讨论】:

    • 我需要了解它,仅此而已。如果确实有实现细节,它可能会有所帮助。但我只是在寻找如何更好地理解它
    • 我是一名计算机工程师,不知道您的问题为何被否决。可能只是因为人们期望代码不起作用。我几乎可以肯定我可以回答你的问题,但仔细想想,我没有。对不起,
    • @EulersIdentity:作为具有数学和计算机科学背景的人,您的问题似乎更像是工程师而不是计算机科学家。您在抽象概念上遇到问题,并试图从有限近似或实现细节的角度进行思考。
    • 顺便说一下,实施细节不太可能有帮助。 CPython 实现使用符号幅度表示。
    • @user2357112supportsMonica 实际上,我的问题看起来像是 Donald Knuth 在他的计算机编程艺术中可能解释的内容......可能不实用,但可以为您的知识增加视角
    猜你喜欢
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 2021-03-20
    相关资源
    最近更新 更多