回顾上一节中,我们讲解了整数的编码规则。
无符号整数编码规则:无符号整数全部都是正数,是什么就存什么。
有符号整数编码规则:有符号整数最高有效位为0是正数,最高有效位为1是负数。
本节内容:原码、反码和补码。
■为什么要有原码、反码和补码:8086 CPU只有加法电路,通过加法电路实现减法、乘法和除法运算。将减法转换为加法运算需要将负数转换为补码,如1-2=1+(-2),-2以其补码形式存储。因此,只有负整数存在原码、反码和补码。
■原码、反码、补码的定义:原码——最高位为符号位,其余各位为数值本身的绝对值。反码——符号位不变,其余各位取反。补码——符号位不变,其余各位取反后加1。
■原码、反码、补码的转换规则:首先指定数据宽度,然后按照定义的规则进行转换。记住圆形数据范围内,左半圆为负整数,右半圆为正整数。
2.6.1 为什么要有原码、反码、补码
由于早期的8086 CPU只支持加法指令,减法、乘法和除法都是通过加法指令实现的。例如:减法运算2-3=?等价于加法运算2+(-3)=?那么剩下的问题就是如何在计算机内存储有符号整数值“-3”。这就需要用到原码、反码和补码的编码规则了。
注意
当算术运算表达式中的两个整数都是无符号整数或者有符号整数的正整数时,不存在减法转加法运算的问题。即原码、反码和补码仅针对于有符号整数的负整数。
再次强调,数据定义一定要指明数据的宽度。
2.6.2 原码、反码、补码的定义
■原码:最高位为符号位,(“0”代表正数,“1”代表负数)其余各位为数值本身的绝对值。
■反码:
正数:反码与原码相同,这是规定。
负数:符号位为1不变,其余位对原码取反。
■补码:
正数:补码与原码相同。
负数:符号位为1不变,其余位对原码取反加1。
举例
例1:写出有符号整数1(8位数据宽度)的原码、反码、补码。
原码:0000 0001 反码:0000 0001 补码:0000 0001
例2:写出有符号整数-1(8位数据宽度)的原码、反码、补码。
原码:1000 0001 反码:1111 1110 补码:1111 1111=>FF
例3:写出有符号整数-7(8位数据宽度)的原码、反码、补码。
原码:1000 0111 反码:1111 1000 补码:1111 1001=>F9
例4:写出有符号整数F9(8位数据宽度)的原码、反码、补码。
原码:1111 1001 反码:1000 0110 补码:1000 0111=>-7
例3和例4,-7的补码是F9,F9的补码是-7,即补码的补码等于自身。
2.6.3 原码、反码和补码的转换规则
■假设数据宽度为1 BYTE(8 BIT)
图2-22 BYTE数据类型存储范围
如图2-22所示:
无符号数:0 1 2 3 4 ......FF
有符号数:
正数:0 .......7F
负数:FF ........80
■假设数据宽度为Doubleword(32BIT)
图2-23 Dword数据类型存储范围
如图2-23所示:
无符号数:0 1 2 3 4 ......FFFFFFFF
有符号数:
正数:0 .......7FFFFFFF
负数:FFFFFFFF ........80000000
■有符号数的编码规则
如果是正数,不变。
如果是负数,分析图2-24所示左右两个半圆部分。
图2-24 32位整数数据范围
分析图2-24有符号整数:
第8位 | 第7位 | 第6位 | 第5位 | 第4位 | 第3位 | 第2位 | 第1位 | |
0XBFFFFFFF | 1011 | 1111 | 1111 | 1111 | 1111 | 1111 | 1111 | 1111 |
0X40000000 | 0100 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 |
表2-9 反码对照表
表2-9中举例说明:圆的左右两边对应的整数互为反码。
■补码为什么要+1
表2-10 4位有符号数-1~-8原码反码补码
表2-11 8位有符号数-1~-8原码反码补码
注意:最高位符号位不参与运算。
表2-10和表2-11分别展示了4位和8位-1~-8的原码、反码和补码的推导过程。符号位不参与运算,保持不变。反码+1后与原码的表示有符号整数值相同。
举例
假设数据宽度为8位。
有符号数-1的补码为:11111111B。
有符号数-3的补码为:11111101B。
1-1=1+(-1)=[00000001B]+[11111111B]=[00000000B]=0发生进位后,数据溢出,舍弃。
5-3=5+(-3)=[00000101B]+[11111101B]=[00000010B]=2。
总结
1.正整数不存在原码、反码和补码的转换,是什么就存什么。
2.只有负整数存在原码、反码和补码的转换。
3.负整数以补码形式存储到内存中,由编译器实现原码、反码和补码的转换。
4.最高位符号位1不参与取反,也不参与有符号数的算术逻辑运算。
练习
1、为什么要有数据宽度?
2、已知0x9A是一个有符号数,那么请说明它是正数还是负数?
3、分别列出 6、-6、7、-7、8、-8、9、-9、1、-1、0、-0 的原码反码补码。
4、已知数据宽度为8Bit,请通过下面的值得到对应原码:
7F 9A 86 5F 3E A3 B7 5D
5、已知数据宽度为32 Bit,请通过下面的值得到对应原码:
0xFFFFFF 0x81234567
6、有符号的正数是原码存储,有符号的负数是补码存储,那么无符号数呢?
7、当计算机中存储的0x81234时,代表的值是多少?
8、假设有符号数数据宽度为8位,其取值范围是-128~127,请问为何负整数取值比正整数多一个值?
本文摘自编程达人系列教材《X86汇编语言基础教程》。