一元“~”运算符 - 这里到底发生了什么?

2022-09-04 02:51:53

我最近做了一个Java课程(1周速成课程),我们涵盖了一些二进制数学。

这个一元~运算符(我想它叫波浪号?)是这样向我们解释的:

它将位模式反转,将每个“0”转换为“1”,将每个“1”转换为“0”。例如,一个字节有8位。如果您有以下字节:00000000,则倒排的值将更改为11111111。

上面的解释清晰简洁,对我来说完全有意义。直到,也就是说,我试图实现它。

鉴于此:

byte x = 3;
byte y = 5;
System.out.println(~x);
System.out.println(~y);

输出为:

-4  
-6

我对这种情况是如何发生的感到非常困惑。

如果二进制中的+3是11,那么这个反转将是00,这显然不是-3。

但是,由于一个字节中有8位,那么+3的二进制表示不应该写成00000011吗?

这将反转成为11111100。转换回十进制值,这将是252。但是,如果您将+3写为011,那么它确实转换为100,即+4,但是您怎么知道它是负数呢?

如果您尝试0011,它将转换为1100,如果您使用第一位作为符号,那么它确实会变成-4。

啊 - 所以在这一点上,我以为我正在到达某个地方。

但后来我得到了y = 5的第二个值。

我们怎么写这个?使用相同的逻辑,+5 转换为二进制 0101,反转为 1010。

现在我感到非常困惑。这看起来表示 -2 的有符号值,或者表示十进制 +10 的无符号值?这两个都不是我正在打印出来的-6。

同样,如果我将长度增加到一个字节的8位数字,则+5 00000101,反转后变为11111010。我真的找不到办法把它变成-6。

有没有人理解这一点,因为我不知道这里发生了什么,我打印出来的数字越多,我就越困惑。

谷歌似乎对此没有提出太多意见 - 也许它不喜欢看小运营商的标志。:-(


答案 1

请参阅此演示: -

3 ->  0011
~3 -> 1100  -> -4 (2's complement)

5 -> 0101
~5 -> 1010 -> -6 (2's complement)

由于有符号整数存储为 2 的补码,因此 take of 会给你 。现在,因为是一个负数。因此,结果是 .的情况也是如此。2's complement110041100-41010

1100 
0011  - 1's complement
0100  - 2's complement  - value = 4 (take negative)

答案 2

来自维基百科:在二的补码表示法中,非负数由其普通的二进制表示表示;在本例中,最高有效位为 0。两者的补码运算是否定运算,因此负数由两者的绝对值的补码表示。
为了获得二进制数的二进制补集,通过使用按位 NOT 运算来反转位或“翻转”位;然后将值 1 添加到结果值中,忽略在取 0 的二进制补码时发生的溢出。http://en.wikipedia.org/wiki/Two%27s_complement

因此,如果你有0101,它是+5,则相反的是1010,即-5。

不过,您并没有真正将010读作5,但是当您在开头看到1时,您知道要获得该数字,您必须再次反转其余数字才能获得要否定的正数。如果这有意义的话。

如果你以前没有使用过它,这有点陌生的概念。这当然不是十进制数的工作方式,但一旦你看到发生了什么,它实际上就很简单了。

小数点后 8 的值写为 01010,不等于 10101。第一个数字 (1) 表示它是负数,然后你翻转其余部分以获得数值:1010。

要记住的一件事是,Two的补码与普通的旧二进制系统计数不同。在正常的二进制中,10101的值(在Two的补码中为-8,如上所述)当然是21。我想这就是混乱的地方 - 你如何通过观察它们来区分?您必须知道使用了哪种表示形式,才能确定数字的实际值。还有一个补充,略有不同。

这里给出了一个关于二进制数学的好教程,包括一和二的补码。http://www.math.grin.edu/~rebelsky/Courses/152/97F/Readings/student-binary


推荐