【问题标题】:~x + ~y == ~(x + y) is always false?~x + ~y == ~(x + y) 总是假的?
【发布时间】:2012-06-22 03:23:03
【问题描述】:

此代码是否总是评估为假?两个变量都是有符号整数的二进制补码。

~x + ~y == ~(x + y)

我觉得应该有一些满足条件的数字。我尝试测试-50005000 之间的数字,但从未达到相等。有没有办法建立一个方程来找到条件的解决方案?

将一个换成另一个会导致我的程序中出现隐蔽的错误吗?

【问题讨论】:

  • 你想要证明还是什么?
  • 请注意,在有符号整数溢出的情况下,它在技术上是未定义的行为。所以它有可能返回true,即使他们永远不能假设严格的二进制补码。
  • @AlvinWong 是的,解释一下会很好
  • @Steve:您可以证明您已经尝试了所有组合中的所有常见嫌疑人(-1、0、1、2 等),以及您尝试“解决”小字长(三位?四位?)的问题。这肯定有助于让我们相信,我们不只是帮助某人获得他们没有首先尝试为自己赚取的东西。 :)
  • @AlexLockwood 当我第一次发布问题时,我假设将问题标记为“家庭作业”要求人们提供帮助我解决问题的线索(如“家庭作业”标签状态的描述)和不只是给出答案。这就是为什么我只是简单地问问题的问题:)

标签: c bit-manipulation signed twos-complement


【解决方案1】:

只考虑xy 的最右边位(即,如果x == 13 是基数为2 的1101,我们将只看最后一位,1)然后有四种可能的情况:

x = 0,y = 0:

LHS:~0 + ~0 => 1 + 1 => 10
右轴:~(0 + 0) => ~0 => 1

x = 0,y = 1:

LHS:~0 + ~1 => 1 + 0 => 1
右轴:~(0 + 1) => ~1 => 0

x = 1,y = 0:

我会留给你,因为这是作业(提示:它与之前的 x 和 y 交换相同)。

x = 1,y = 1:

我也会把这个留给你。

在给定任何可能的输入的情况下,您可以证明等式左侧和右侧的最右边的位总是不同的,因此您已经证明两边不相等,因为它们至少有那个位是相互翻转的。

【讨论】:

    【解决方案2】:

    啊,基础离散数学!

    查看De Morgan's Law

    ~x & ~y == ~(x | y)
    
    ~x | ~y == ~(x & y)
    

    对于布尔证明非常重要!

    【讨论】:

    • 完全错了。在 C + 中是加法,* 乘法而不是布尔或或与。
    • 感谢您指出不正确的运算符,nalply。它现在已使用正确的运算符进行了更新,尽管您是正确的,它不适用于原始问题。
    • 好吧,如果 true 为 1,false 为 0,那么 + 和 * 的行为与 or 和 and 完全一样,而且二进制补码的行为类似于 not,因此仍然适用法律。
    • 感谢您指出这一点,a1an。我试图思考德摩根定律如何仍然适用于最初的问题,但自从我学习 C 编程或离散数学以来已经有好几年了。
    【解决方案3】:

    C 不要求二进制补码是实现的。但是,对于无符号整数,应用了类似的逻辑。在这个逻辑下,差异永远是 1!

    【讨论】:

      【解决方案4】:

      MAX_INT 成为由011111...111 表示的整数(不管有多少位)。那么你知道~x + x = MAX_INT~y + y = MAX_INT,所以你肯定知道~x + ~y~(x + y)之间的区别是1

      【讨论】:

        【解决方案5】:

        当然,C 不需要这种行为,因为它不需要二进制补码表示。例如~x = (2^n - 1) - x & ~y = (2^n - 1) - y 会得到这个结果。

        【讨论】:

          【解决方案6】:

          二的补码

          大量大多数计算机上,如果x 是整数,则-x 表示为~x + 1。等效地,~x == -(x + 1)。在你的等式中进行这个代入给出:

          • ~x + ~y == ~(x + y)
          • -(x+1) + -(y+1) = -((x + y) + 1)
          • -x - y - 2 = -x - y - 1
          • -2 = -1

          这是一个矛盾,所以~x + ~y == ~(x + y) 总是false


          也就是说,学究们会指出C不需要补码,所以我们还必须考虑......

          一个人的补充

          one's complement 中,-x 被简单地表示为~x。零是一种特殊情况,同时具有全 0 (+0) 和全 1 (-0) 表示,但 IIRC、C 需要 +0 == -0,即使它们具有不同的位模式,所以这不应该是问题。只需将~ 替换为-

          • ~x + ~y == ~(x + y)
          • -x + (-y) = -(x + y)

          这对于所有xy 都是true

          【讨论】:

          • +1 表示实际上同时考虑二进制补码和一个补码的答案。
          • @dan04,+0 == -0。最后是在 C 中有意义的东西。:)
          【解决方案7】:

          提示:

          x + ~x = -1 (mod 2n)

          假设问题的目标是测试您的数学(而不是您阅读 C 规范的技能),这应该可以帮助您找到答案。

          【讨论】:

          • 仅在补码机器上。 (C 标准不要求)
          • @Billy:这就像在说“只适用于两个武装的人”。
          • @dan04:不,不是。我想说所有带符号的幅度和补码表示都已从世界上消失了。但我这样说是错的。 C 标准不允许您做出这样的假设。因此,我会说做出这种假设的代码大多数时候都是糟糕的代码。 (特别是当通常有更好的方法来处理有符号数字而不是位旋转时;尤其是当无符号数字在大多数情况下可能是更好的选择时)
          【解决方案8】:

          为了矛盾起见,假设存在一些 x 和一些 y (mod 2n) 使得

          ~(x+y) == ~x + ~y
          

          通过补码*,我们知道,

                -x == ~x + 1
          <==>  -1 == ~x + x
          

          注意到这个结果,我们有,

                ~(x+y) == ~x + ~y
          <==>  ~(x+y) + (x+y) == ~x + ~y + (x+y)
          <==>  ~(x+y) + (x+y) == (~x + x) + (~y + y)
          <==>  ~(x+y) + (x+y) == -1 + -1
          <==>  ~(x+y) + (x+y) == -2
          <==>  -1 == -2
          

          因此,矛盾。因此,~(x+y) != ~x + ~y 适用于所有 xy(mod 2n)。


          *有趣的是,在具有补码算法的机器上,等式实际上适用于所有xy。这是因为在一个补码下,~x = -x。因此,~x + ~y == -x + -y == -(x+y) == ~(x+y).

          【讨论】:

          • 当然,C 不需要这种行为;因为它不需要二进制补码表示。
          • 顺便说一句,等式是 true 的补码。通常,NOT 运算并没有真正为数字定义,因此将 NOT 与加法混合会导致不同的行为,具体取决于数字的表示。
          • 可以将问题重述为 无符号整数,然后二进制补码根本不起作用。
          • 更简单,恕我直言:~x == -(x+1),所以~(x+y) == ~x + ~y 暗示-(x+y+1) == -(x+1) + -(y+1) 暗示-1 == -2
          • @BillyONEal,别担心,我只是在开玩笑,我很感激你提到它:)。我会在我遇到一台执行补码算术的机器的那一天请你喝一杯……听起来怎么样?哈哈
          【解决方案9】:

          在 one's 和 two's(甚至是 42's)补码中,都可以证明:

          ~x + ~y == ~(x + a) + ~(y - a)
          

          现在让a = y 我们有:

          ~x + ~y == ~(x + y) + ~(y - y)
          

          或:

          ~x + ~y == ~(x + y) + ~0
          

          因此在~0 = -1的二进制补码中,命题为假。

          ~0 = 0 的补码中,命题为真。

          【讨论】:

            【解决方案10】:

            根据 Dennis Ritchie 的书,C 默认情况下不实现补码。因此,您的问题可能并不总是正确的。

            【讨论】:

              【解决方案11】:

              如果位数为n

              ~x = (2^n - 1) - x
              ~y = (2^n - 1) - y
              
              
              ~x + ~y = (2^n - 1) +(2^n - 1) - x - y =>  (2^n + (2^n - 1) - x - y ) - 1 => modulo: (2^n - 1) - x - y - 1.
              

              现在,

               ~(x + y) = (2^n - 1) - (x + y) = (2^n - 1) - x - y.
              

              因此,它们总是不相等的,相差 1。

              【讨论】:

              • @nhahtdh 你如何定义对非固定宽度数字的~ 操作?
              • 我用这些位数给出了这个答案,以便很容易与课堂上所教的内容相关联。请注意,~x 高度依赖于用于表示数字的位数 n。因此,在尝试通过实验验证这一点时,坚持一个是明智的。
              • @hamstergene:我知道位数是固定的,但我的意思是它不必是那些数量(8、16 等)。
              • 这些值很容易编写程序来验证答案。它适用于任何 n,只要写入 ~x 和 ~y 以匹配给定的 .
              • @hamstergene:我对证明没有问题,只是这些数字给出了错误的暗示,即它只适用于这些情况。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-05-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-02-26
              • 1970-01-01
              相关资源
              最近更新 更多