前一篇文章中,我提到了,在研究一个问题的时候,顺便了解了 Java 的 int 溢出处理。其实,在研究时,还涉及到了另一个概念的理解,那就是 Java 中负数的二进制表现形式: 二补码
(英文为 Two's Complement
),在这篇文章中我们来了解一下。
开始之前,我们先来回顾两个规则:
好,复习完了这两条规则,我们开始吧,我们先来说结论,在 Java 中,负数转正数或者正数转负数的操作都是用的 二补码
这个操作,这个操作内容就是: 按位取反 + 二进制1
,我们来看一个例子。
// 十进制数 1640531527 // 1640531527 转为二进制 01100001110010001000011001000111 // 1640531527 按位取反 10011110001101110111100110111000 // 二进制的 1 00000000000000000000000000000001 // 二进制加法 1640531527 按位取反后的数 + 1 10011110001101110111100110111000 + 00000000000000000000000000000001 ----------------------------------- = 10011110001101110111100110111001 // 最后的到的 10011110001101110111100110111001 从新转为 10 进制 -1640531527
上边的过程用 Java 代码表示:
System.out.println(~0b01100001110010001000011001000111 + 0b00000000000000000000000000000001);
关于负数正数,为什么是按位取反再加一这种规则,再多写一些,看了阮一峰的一篇文章,了解到的:
// 大家可以想一下,设 a = 1640531527,取取负数 b ,可以用 b = 0 - a 来实现,换成二进制运算如下 // 二进制的 0 00000000000000000000000000000000 // 二进制的 1640531527 01100001110010001000011001000111 // 二进制的减法 0 - 1640531527 00000000000000000000000000000000 - 01100001110010001000011001000111 ----------------------------------- =? // 在上边的算式里,你会发现,没法减,下边的数比上边的大,想要减需要借位,也就是变成下边这样 100000000000000000000000000000000 - 01100001110010001000011001000111 ----------------------------------- = 10011110001101110111100110111000 // 上边的算式中,被减数是凭空接了 1 位的,这样就够减了,其实大家仔细观察一下,100000000000000000000000000000000 减 01100001110010001000011001000111 后得到的 10011110001101110111100110111000 实际上就是 01100001110010001000011001000111 按位取了一下反 // 我们再来观察一下 100000000000000000000000000000000 是可以按下面的式子分解的 100000000000000000000000000000000 = 11111111111111111111111111111111 + 00000000000000000000000000000001 // 那么,其实上边的减法我们可以化为如下形式 11111111111111111111111111111111 + 00000000000000000000000000000001 ----------------------------------- = 100000000000000000000000000000000 - 01100001110010001000011001000111 ----------------------------------- = 10011110001101110111100110111000 // 再清晰一些:我们设 a = 01100001110010001000011001000111,求 -a,那么就是 -a = 0 - a -a = (11111111111111111111111111111111 + 00000000000000000000000000000001) - a -a = (11111111111111111111111111111111 - a) + 00000000000000000000000000000001 // 上边的式子就很清楚了 11111111111111111111111111111111 - a 其实就是把 a 按位取反,而后边加上了 00000000000000000000000000000001 就是 + 1,也就是正数转负数(负数转正数)就是按位取反再加一 -a = ~a + 1