【问题标题】:Does the bitwise operators XOR and OR works differently on negative numbers unlike AND operator与 AND 运算符不同,按位运算符 XOR 和 OR 对负数的工作方式是否不同
【发布时间】:2021-05-07 16:48:28
【问题描述】:

我尝试了各种组合以更好地理解 XOR 运算符,但我无法弄清楚在负数的情况下按位实际上是如何工作的,因为在正数的情况下它很好(如预期的那样)但产生在对负数应用相同的逻辑时,按位与(&)、按位异或(^)和按位或(|)情况下的结果不同。

如果是正数:

x = 26;
y = 3;
System.out.println(x ^ y); // 25
System.out.println(x & y); // 2
System.out.println(x | y); // 27

11010 -> 26
00011 -> 3

Applying XOR    Applying AND    Applying OR
11010           11010           11010
00011           00011           00011
-----           -----           -----
11001 -> 25     00010 -> 2      11011 -> 27

手动分析时的预期输出。

但是,如果是负数:

x = 26;
y = -3;
System.out.println(x ^ y); // -25
System.out.println(x & y); // 24
System.out.println(x | y); // -1


00000000000000000000000000011010 --> 26
11111111111111111111111111111101 --> -3(2s complement of -3)

         Applying XOR                            Applying OR       
00000000000000000000000000011010       00000000000000000000000000011010            
11111111111111111111111111111101       11111111111111111111111111111101            
--------------------------------       --------------------------------        
11111111111111111111111111100111       11111111111111111111111111111111

(不是预期的输出,因为在手动分析时它会给出不同的输出,因为如果我将 XOR(11111111111111111111111111100111) 和 OR(11111111111111111111111111111111) 的结果转换为十进制,那么它将给出一个巨大的数字,这与预期的输出相去甚远)

任何我不熟悉的内部正在做什么的建议,或者在负数的情况下按位 XOR(|)、AND(&) 和 OR(|) 的功能

【问题讨论】:

  • 为什么你认为 11010 可以表示 26 而 11101 可以表示 -3 在相同的表示中?要么都是负数,要么都不是负数。
  • 换句话说,你任意决定用 5 位而不是 32 位来表示数字,这会让你错过一些关于这些数字的关键上下文。
  • @FedericoklezCulloca 我知道它们用 32 位表示,如果我在前面应用 0 和 1 并对 26 和 -3 位进行 XOR 或 OR 运算,即使那样我也没有得到手动分析时的预期输出。
  • 您希望负数的结果是什么?你向我们展示了结果是什么,但没有告诉我们你为什么期望它们不同或你期望它们是什么。
  • 好的,所以问题不在于代码。问题在于您在脑海中进行的计算。正确公式:-2^32 + (2^31 + 2^30 + ...)。对于负数,填充 32 位中的第一个。因此,您从其余位中减去第一个(负)位。根据您的公式,-3 在二进制中也是一个巨大的数字,您为什么不感到惊讶?

标签: java bit-manipulation bitwise-operators


【解决方案1】:

当数字为负数时,这就是数字在内部存储的方式。例如:

System.out.println(Integer.toBinaryString(26));
System.out.println(Integer.toBinaryString(-3));

将输出:

0000000.............0000...11010 // the zeros in front are not shown
11111111111111111111111111111101

所以现在应该明白当你XORAND 时会发生什么。它们用32 bits 表示,这就是您的误解所在。

【讨论】:

  • 我知道它们用 32 位表示,如果我在前面应用 0 和 1 并对 26 和 -3 位执行 XOR 或 OR 运算,即使这样我也没有得到预期的输出手动分析时。您可以使用提供的输出检查相同的内容并对它们应用 XOR 运算(26 和 -3 的二进制数字)并尝试将它们转换为十进制(通过手动执行)
  • @AkshayaAmar:我认为你的错误是假设它们是usigned,你将它们转换为十进制! (即直接二进制到十进制转换),但它们当然是有符号的。这意味着您必须考虑符号位并采用 2s 补码(正如您在问题中提到的那样)。 11111111111111111111111111100111 当然是 -25 而不是“一些巨大的数字”。
  • @JoachimSauer 我没有立即将十进制转换为二进制...首先我通过反转二进制取出 1s 的补码,然后通过将 1 添加到反转的二进制中取出 2s,然后开始执行操作( XOR 或 OR)在它们上,我在两个操作数上应用 ^ 时也得到 -25(以编程方式),但是当手动将二进制输出转换为十进制时,我无法转换并获得所需的 -25 输出。成为一个大数字
  • @JoachimSauer 当将十进制转换为二进制时,即 System.out.println(Integer.toBinaryString(-25)) 给出 111111111111111111111111111100111(这是预期的)但由 System.out 反转(二进制返回十进制) .println(Integer.parseInt("1111111111111111111111111100111", 2));正在生产 2147483623(大数字)而不是 -25
  • @AkshayaAmar:应该注意的是,可以只写-11001 来表示二进制的-25,但这种表示法非常罕见,因为它实际上并不help: 二进制对于人类来说很难使用,当计算机使用它们时,它们使用 2s 补码(即它们没有- 符号,它们只需要知道给定的 32 位值应该被解释为签)。所以toBinaryString 有效地输出“无符号二进制”(即解释这些位,就好像它们没有符号一样),这恰好是它们实际存储在内存中的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-13
  • 2011-02-10
  • 1970-01-01
  • 2015-02-26
  • 2014-09-04
  • 2020-12-17
  • 1970-01-01
相关资源
最近更新 更多