您的浏览器过于古老 & 陈旧。为了更好的访问体验, 请 升级你的浏览器
Ready 发布于2013年08月28日 08:46

原创 计算机二进制以及原码、反码、补码入门详解

4005 次浏览 读完需要≈ 11 分钟

内容目录

二进制,是一种广泛应用于现代计算机技术的数制。众所周知,我们常用的十进制是“逢十进一”的,我们只需要使用0、1、2、3、4、5、6、7、8、9这10个数字符号,就能表示所有的自然数。与此类似,二进制是“逢二进一”的进位制,它只需要使用0、1这两个数字符号,就能表示所有的自然数。

对于习惯于使用十进制的我们而言,十进制是非常易于理解的,看起来简洁直观,使用起来也方便简单。为什么计算机不和我们也同样使用的十进制,而要使用一种新的、常人难以理解的二进制呢?

众所周知,具有表示两种稳定状态的元件(如晶体管的导通和截止、继电器的接通和断开、电极的正负、电脉冲电平的高低等)很容易找到,但是想要找到一种具备10种稳定状态的元件来表示十进制的10个数字符号就非常困难了。因此,现代电子计算机技术中全部采用的是二进制。对于计算机而言,二进制只使用0、1两个数字符号,非常简单方便,易于用电子方式实现。不管是我们平常看到的影音、图片还是中文、数字,在计算机内部处理的信息,都是采用二进制数来表示的。

对于经常与计算机打交道的程序开发人员来而言,更好地理解计算机二进制是大有裨益的。

由于在计算机二进制中,只有0、1两个数字符号,因此十进制的25转换为二进制形式将如下表示:

十进制到二进制的转换

在十进制中,整数25可以分解为如下代码:

//例1:十进制
25 = 2 * 101 + 5 * 100 = 2 * 10 + 5 * 1 = 20 + 5;

类似的,在二进制中,11001可以分解为如下代码:

//例2:二进制
1 1001 = 1 * 24 + 1 * 23 + 0 * 22 + 0 * 21 + 1 * 20
= 1 * 16 + 1 * 8 + 0 * 4 + 0 * 2 + 1 * 1 = 16 + 8 + 0 + 0 + 1;

通过上面的例子,相信读者都应该清楚十进制和二进制之间的一般转换方法了。

bit(位/位元)与byte(字节)

在电子计算机中,二进制位用单位bit(binary digit的缩写,中文:位或位元,中文版发音:比特)来表示,1 bit表示一个二进制位,它也是数据信息的最小计量单位。而我们常用的容量单位byte(字节)与bit一般具有如下换算关系:

//例3
1 byte = 8 bit;

一个字节(byte)实际上就是一个长度为8的二进制数,它可以用来表示256(28)个数,例如(本文中,二进制每隔4位空一格,以便于阅读区分):

//例4
0000 0000(二进制) 表示 0(十进制)
0000 0001(二进制) 表示 1(十进制)
0000 0111(二进制) 表示 7(十进制)
...
11111111(二进制) 表示 255(十进制)

不过,在大多数计算机编程语言中,一个byte所表示的数却并不是这个范围,毕竟我们还需要考虑到负数的情况。于是计算机的先驱们又想到,用8位二进制的左侧第1位来表示正负符号位,如果左边第一位为0,则表示为正;如果左边第一位为1,则表示为负。于是byte可用来表示成如下范围的数:

//例5
1111 1111(二进制) 表示 -127(十进制)
1111 1110(二进制) 表示 -126(十进制)
...
1000 0001(二进制) 表示 -1(十进制)
1000 0000(二进制) 表示 0(十进制)
0000 0000(二进制) 表示 0(十进制)
0000 0001(二进制) 表示 1(十进制)
0000 0010(二进制) 表示 2(十进制)
...
01111110(二进制) 表示 126(十进制)
01111111(二进制) 表示 127(十进制)

比较细心的读者应该发现,新的问题又诞生了,在上述byte表示范围的例子中,二进制1000 0000与0000 0000都表示十进制0。这样的话,在计算中就出现了重复表示同一个数的情况。也就是说,每个byte中都存在一种浪费空间的表示形式。对于追求完美的计算机先驱们来说,这样的设计和空间浪费是不能容忍的,更何况在计算机出现的早期,当时的内存和磁盘空间容量都非常小,并且价格昂贵,可谓是寸土寸金,更不要奢望像现在这样——GB、TB、PB都不是什么新鲜事儿。

于是,聪明的计算机设计先驱们提出了原码、反码、补码等概念,并以补码的形式比较好地解决了这个问题。那么什么是原码、反码和补码呢?

原码

原码,顾名思义,就是"未经任何更改"的码。说得简单点,就是一个二进制数它自身,也就是上面例6中的所展示的代码形式。它的左侧首位依然表示正负符号位,后面就是该数在数学上原原本本的二进制表现形式。例如,十进制数的二进制原码表现形式举例如下:

//例6
17的原码:
0001 0001
5的原码:
0000 0101
-7的原码:
1000 0111
-13的原码:
1000 1101

反码

那么,什么是反码呢?顾名思义,就是“相反”的码。 反码表示法的规定如下:

  1. 非负数的反码与原码相同。
  2. 负数的反码就是:除了符号位外,其他所有位上的数字和原码完全相反,如果原码某位上的数字是1,那么反码对应位上的数字就是0;如果原码某位上的数字是0,那么反码对应位上的数字就是1。

例如,上面例6中的反码表现形式如下:

//例7
17的原码:
0001 0001
17的反码(非负数的反码与原码相同):
0001 0001

5的原码:
0000 0101
5的反码:
0000 0101

-7的原码:
1000 0111
-7的反码(负数的反码:在原码的基础上,符号位不变,其他位逐位取反):
1111 1000

-13的原码:
1000 1101
-13的反码:
1111 0010

补码

补码表示法的规定如下:

  1. 非负数的补码都与原码相同。
  2. 负数的补码就是:符号位仍然保持不变,符号位后的二进制数值在反码的基础上数值加1。

例如上面例7中的补码表现形式如下:

//例8
17的原码:
0001 0001
17的反码:
0001 0001
17的补码(非负数的补码与原码相同):
0001 0001

5的原码:
0000 0101
5的反码:
0000 0101
5的补码:
0000 0101

-7的原码:
1000 0111
-7的反码:
1111 1000
-7的补码(负数的补码就是:符号位不变,将符号位后面的反码数值加1):
1111 1001

-13的原码:
1000 1101
-13的反码:
1111 0010
-13的补码:
1111 0011

值得注意的是,除符号位之外,如果后面其他位数值加1,造成最高位(符号位的右边1位)有进位,则进位将会舍弃。例如原码为1000 0000的8位二进制数,它的反码为1111 1111,那么它的补码为1000 0000(符号位后的"111 1111",加上1为"1000 0000",最高位进位,舍弃掉进位的"1",得到"000 0000",前面加上符号位"1",即得到"1000 0000")。

为了充分合理地利用所有的空间,在计算机系统中,所有的数值一律用它的补码来表示并存储。下面举例说明:

12(十进制):
其8位二进制原码为0000 1100,由于12为非负数,所以其补码为0000 1100,因此12在内存中的表现形式为:0000 1100

-3(十进制):
其8位二进制原码为1000 0011,由于其为负数,所以-3的反码为1111 1100,它的补码为1111 1101,因此-3在内存中的表现形式为:1111 1101

如果,内存中一个8位二进制数X的表现形式为:1110 1011,由于计算机系统中的数值都是以其补码形式存储的,即表示X的补码为:1110 1011。
由于非负数的反码、补码与原码相同,符号位不可能为负,所以X只能为负数。
由于负数的补码是除符号位之后的反码数值加上1得来的,所以X的反码为:1110 1010。
由于负数的反码是除符号位之外的原码诸位取反的来的,所以X的原码为:1001 0101。
X的原码为1001 0101,那么除符号位之外的二进制位1 0101,通过转换可以计算出对应的十进制数为21。又因为符号位为1(负),所以X的十进制形式为-21。

备注:熟悉编程语言的人应该都知道,实际上除了byte(8位二进制)外,还有short(16位二进制)、int(32位二进制)、long(64位二进制)等多种表现形式。为了更易于读者理解,本文的示例均以8位二进制(byte)为例来介绍。其他类型也与此类似,只是最大位数有所不同。

总结如下:
1.二进制的最高位(左侧第1位)为符号位,0表示正数,1表示负数。
2.非负数的反码、补码与原码相同。
3.负数的反码=它的原码的符号位不变,其他位逐位取反(是0的变成1,是1的变成0)。
4.负数的补码=它的反码的符号位不变,符号位之后的数值+1。
5.在计算机系统中,所有的数值都是以补码形式来表示的。

  • CodePlayer技术交流群1
  • CodePlayer技术交流群2

0 条评论

撰写评论