原文:https://blog.csdn.net/jiangjieqazwsx/article/details/79942079
在计算机中,数据有三种形式:原码、反码和补码,要弄清楚补码的计算方法,首先让我们来了解三种形式的定义。
1、原码
如果机器字长为n,那么一个数的原码就是用一个n位的二进制数,其中最高位为符号位:正数为0,负数为1。剩下的n-1位表示该数的绝对值(此处假设机器长度为8)。
例如:
X=+7 , [X]原= 0000 0111
X=-7 , [X]原= 1000 0111
位数不够的用0补全。
PS:正数的原、反、补码都一样,0的原码跟反码都有两个,因为这里0被分为+0和-0。
2、反码
反码就是在原码的基础上,符号位不变其他位按位取反(就是0变1,1变0)就可以了。
例如:
X=-7 , [X]原= 1000 0111 ,[X]反=1111 1000
3、补码
补码也非常的简单,就是在反码的基础上按照正常的加法运算加1。
例如:
X=-7 , [X]原= 1000 0111 ,[X]反=1111 1000,[X]补=11111001
PS:0的补码是唯一的,如果机器字长为8那么[0]补=0000 0000。
在计算补码的时候,楼主一般这么记忆:
正数的原码、反码和补码是一个;
负数补码的计算方法:负数的绝对值对应的二进制数进行取反加一即可。
从前面的三种码型的定义,我们可以看出数据的原码,使用符号位来区分了正负数,更加符合人脑直观识别并且用于计算的表达方式。但是在计算机中,通过补码的形式保存数据,这是为什么了?下面我们进行探讨一下。
在我们的计算中,使用最基础的运算就是加减乘除了,因此最好设计得尽量简单,计算机辨别"符号位"会让计算机的基础电路设计变得复杂,于是,人们想出了将符号位也参与运算的方法。
我们知道,根据运算法则,减去一个正数等于加上一个负数,即:1-1 = 1 + (-1),所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单了。
但是,用原码计算时有一些问题...
于是人们就开始探索将符号位参与运算并且只保留加法的方法。
首先来看原码:
1 - 1 = 1 + (-1) =[0000_0001]原 + [1000_0001]原 = [1000_0010]原 = -2
如果用原码表示, 让符号位也参与计算,显然对于减法来说结果是不正确的。
这也就是为何计算机内部不使用原码表示一个数。
于是,反码出现了,但还有问题...
为了解决原码做减法的问题,出现了反码:
1 - 1 = 1 + (-1) =[0000_0001]原 + [1000_0001]原= [0000_0001]反 + [1111_1110]反 = [1111_1111]反
= [1000_0000]原 = -0
发现用反码计算减法,结果的真值部分是正确的,而唯一的问题其实就出现在"0"这个特殊的数值上。虽然人们理解上+0和-0是一样的,但是0带符号是没有任何意义的,而且会有[0000_0000]原和[1000_0000]原两个编码表示0。
补码解决了遗留的这个问题..
于是补码出现了,它解决了0的符号以及两个编码的问题:
1-1 = 1 + (-1) =[0000_0001]原 + [1000_0001]原 = [0000_0001]补 + [1111_1111]补 = [0000_0000]补
=[0000_0000]原 = 0
这样0用[0000_0000]表示,而以前出现问题的-0则不存在了。
除此之外,还可以用 [1000_0000]补 表示-128:
(-1) + (-127) =[1000_0001]原 + [1111_1111]原 = [1111_1111]补 + [1000_0001]补 = [1000_0000]补
-1-127的结果应该是-128,在用补码运算的结果中, [1000_0000]补 就代表-128。
注意,-128并没有原码和反码表示。
使用补码不仅仅修复了0的符号以及存在两个编码的问题,而且还能够多表示一个最低数,这就是为什么8位二进制使用原码或反码表示的范围为 [-127, +127],而使用补码表示的范围为 [-128, 127] 的原因。
因为机器使用补码,所以对于编程中常用到的32位int类型可以表示范围是 [-2^31,2^31-1] ,因为第一位表示的是符号位,而使用补码表示时又可以多保存一个最小值。