转载

关于'二补码'(Two's Complement)

前一篇文章中,我提到了,在研究一个问题的时候,顺便了解了 Java 的 int 溢出处理。其实,在研究时,还涉及到了另一个概念的理解,那就是 Java 中负数的二进制表现形式: 二补码 (英文为 Two's Complement ),在这篇文章中我们来了解一下。

正文

开始之前,我们先来回顾两个规则:

  • 在 Java 中,全部为有符号数,最高位为符号位,0代表正数,1代表负数
  • 在 Java 中 int 为 32位。

好,复习完了这两条规则,我们开始吧,我们先来说结论,在 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
原文  https://since1986.github.io/blog/f89c2671.html
正文到此结束
Loading...