计算机基础知识--原码、反码、补码

585 阅读4分钟

原码

一个数的二进制表现形式就是这个数的原码。

比如:

3 -> 00000011

其中,原码的最高位是符号位,代表数据的正负,0代表正,1代表负

对于正数的计算,使用原码运算不会有任何问题,例如

3+2=5

 00000011
+00000010
-----------
 00000101

但如果有负数参与计算,结果就会大跌眼镜,例如

-3+2=-1

 10000011
+00000010
-----------
 10000101

转化为十进制,结果等于-5,这显然不是正确结果。

为了解决负数的计算问题,反码和补码就诞生了

反码

  • 正数的反码与原码相同

  • 负数的反码是该数的绝对值的原码按位取反,即0变成1,1变成0,但符号位不变

补码

  • 正数的补码和原码相同
  • 负数的补码是该数的反码,然后加1

知道了反码和补码的概念之后,我们还需要知道一个很重要的基础知识

计算机是以一个数的补码来进行计算和存储的。

因为正数的补码、原码、反码都是一样的,所以,按照原码运算是没有问题的,但是负数的补码跟原码不一样,所以上面我们计算-3+2的思路其实是错误的,正确计算过程应该先将两个数的补码计算出来,然后通过补码进行运算,得到的结果再转化成十进制,具体过程如下:

1、先表示出-3的反码,即3的原码按位取反,符号位不变
    3的原码为
    00000011
    取反后为
    01111100
    恢复符号位
    11111100
2、再表示出-3的补码,即-3的反码,然后加1
    反码上面已经运算得到为
    11111100
    加1后变为
    11111101
3、将-3和2的补码进行加法运算
    11111101
   +00000010
   ----------
    11111111
   注意这里得到的是结果的补码,很显然是一个负数,因为高位为1,这时我们要将补码还原成原码,就是将补码的计算过程反过来执行一遍
   先取反(包括符号位)得到
    00000000
   再加1,为
    00000001
   最后加上负数符号位1,为
    10000001
   转化为十进制即为-1,所以-3+2=-1,结果正确
   

实战演练

我们知道,在java中,byte的取值范围是[-128,127],那么你有没有想过,这两个范围值是怎么计算出来的呢

首先,因为一个byte数占一个字节,一个字节占8位,其中第一位为符号位,0代表正数,1代表负数,所以,byte在计算机中的最大值为01111111,注意,因为计算机存储的是补码,所以这个01111111是最大值的补码,并不是原码,然后需要根据补码计算出原码,而正数的原码和补码相同,所以原码也为01111111,转化为十进制即为127;

同理,byte在计算机中的最小值为10000000,有很多人想不通,难道不是11111111吗,这里请注意,这种想法实际上是现实中的思维,在计算机思维中,符号位和数值位是独立的,每一位要么取1,要么取0,数值位中,求最大则取1,求最小则取0;符号位中,求最大则取0(因为0代表正数),求最小则取1(因为1代表负数),所以计算机认为10000000才是byte中最小的数(因为符号位和数值位均取最小值),再根据补码计算出原码(即求出该数的十进制值),对补码取反后加1,10000000取反为01111111,即127,再加1为128,加上补码前面的符号位,即为-128。

小结

关于原码、补码、反码,属于计算机的基础知识,在位运算时我们会用到,但实际开发过程中很少使用位运算,实际上位运算比四则运算要快很多,掌握此知识点能给我们的优化思路提供新的方向。