我最近做了一门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的方法。
有没有人明白这一点,因为我不知道这里发生了什么,我打印的数字越多,我就越困惑。
谷歌似乎没有提出任何相关内容 - 也许它不喜欢看小运营商的迹象......: - (
答案 0 :(得分:8)
见这个演示: -
3 -> 0011
~3 -> 1100 -> -4 (2's complement)
5 -> 0101
~5 -> 1010 -> -6 (2's complement)
由于有符号整数存储为2的补码,因此2's complement
的{{1}}会为1100
提供4
。现在1100
是一个负数。所以,结果是-4
。 1010
的情况也是如此。
1100
0011 - 1's complement
0100 - 2's complement - value = 4 (take negative)
答案 1 :(得分:4)
来自维基百科:在二进制补码表示法中,非负数用其普通的二进制表示法表示;在这种情况下,最高有效位为0.二进制补码操作是否定操作,因此负数由绝对值的二进制补码表示。
为了获得二进制数的二进制补码,通过使用按位NOT运算来反转或“翻转”这些位;然后将值1添加到结果值中,忽略在取两个补码0时发生的溢出。http://en.wikipedia.org/wiki/Two%27s_complement
所以如果你有0101这是+5,那么它的倒数是1010,即-5。
虽然你没有真正读取010作为5,但是当你在开头看到1时,你知道要获得数字你必须再次反转其余的数字以得到你的正数想要否定。如果这是有道理的。
如果您以前没有使用它,这是一个外星人的概念。这当然不是十进制数字的工作方式,但一旦你看到发生了什么,它实际上很简单。
值为8十进制写为01010,否定为10101.第一个数字(1)表示它为负数,然后将其余部分翻转以获取数值:1010。
要记住的一点是,二进制补码与普通的旧二进制系统计数不同。在正常二进制中,10101的值(在二进制补码中是-8,如上所述)当然是21.我想这就是混乱的来源 - 你如何通过观察它们来区分它们?您必须知道使用了哪种表示形式才能确定数字的实际值。还有一个补码略有不同。
这里给出了关于二进制数学的好教程,包括One和Two的补码。 http://www.math.grin.edu/~rebelsky/Courses/152/97F/Readings/student-binary
答案 2 :(得分:2)
使用twos complement几乎普遍存储有符号整数。这意味着反转位(取一个补码)并加一个。这样,您就没有两个整数零(+0和-0)的表示,并且某些签名操作变得更容易在硬件中实现。
答案 3 :(得分:2)
Java在Two's complement中使用带符号的数字。当使用类型为“unsigned int”或“unsigned char”时,您的推理在C或其他语言中是正确的。