一.有符号数的加减法
1、符号数与无符号数的人为规定性:
一个数,是有符号数还是无符号数都是人为规定的。进行二进制运算时用无符号数或是补码运算时,结果都是正确的。
10000100+00001110
若规定为无符号数,即 132+146=146D 。
若规定为符号数,则为-124+14=-110,而[-110]补=10010010。解释:10000100是 -124的补码,0001110是14的补码,在机器中运算后得出的结果是[-110]的补码。机器中的有符号数的运算一般就是补码的运算。
2、补码加减法运算
计算机中,当确定为符号数运算时,符号数一律用补码表示,运算时符号位和数字位一起参加运算。同样,运算结果也用补码表示。
1)两符号数相加公式:
[X+Y]补=[X]补+[Y]补
2)两符号数相减公式:
[X-Y]补=[X]补+[-Y]补
3.例子:
求3CH-90H。
首先3CH=0011 1100,90H=1001 0000
(1)当为有符号数时,显然这两个数是某两个数的补码。(具体是哪两个数X Y, 需要自己计算)。运算结果也是补码,是X-Y的补码 [X-Y]补。机器只运算到这一步。[X-Y]补 就是运算结果,溢出 进位等标志位也都是这个补码运算过程的结果,由硬件ALU运算。X-Y并不是机器的运算结果,由[X-Y]补求X-Y是人或者编译器完成的工作,对于编译器来说运算结果才是X-Y。
补码的减法要转换成补码的加法。
根据有符号数的减法公式,[x]补-[Y]补=[x]补+[-Y]补=[X-Y]补,
[x]补=0011 1100,[Y]补=1001 0000,其中求[-Y]补是关键。
[-Y]补= {-[Y]补} mod 2^8,即[-Y]补={-[Y]补} 的求补操作(即-[Y]补 的补码)(即 按位取反再加一,这是机器真正的过程)。
所以,[-Y]补=0111 0000,
所以,[X-Y]补=0011 1100-1001 0000=0011 1100+0111 0000=ACH
(2)补码最大好处就是不管是有符号数还是无符号数都可以用同一套加减法。系统对有符号数和无符号数的加减法都采用一样的策略。
无符号加减法不存在溢出问题,只是将进位或借位存储在CF中。
机器不知道你进行的运算是否有符号,如果你进行的是有符号运算,你需要查看OF,否则不需要。
所以,溢出不溢出,是由程序员判断的,机器不知道。
不管是有符号数还是无符号数,系统都是按补码运算,至于是进位还是溢出不仅要看进位标志位,还要看溢出标志位。
只不过在做无符号数运算时程序员不考虑溢出标志位,只考虑进位标志位而已。
比如0111+1101,你说它是无符号数7+13呢,还是有符号数7-3呢?
对系统而言这是一回事!
所以,无符号数时,和有符号数时的运算结果一定是一样的。
(3)注意这道题和《计算机组成原理》学补码加减运算时的题目的区别。
例子:X=+0101,Y=-1010,求X-Y。
题目给的X Y,是原码, 所以已经默认是有符号数,也有判断是否溢出,所以默认的计算过程也是指机器运算过程。
原码在机器中 均是以补码保存和运算的,
[x]补-[Y]补=[x]补+[-Y]补=[X-Y]补,只用到了[x]补+[-Y]补=[X-Y]补
属于类型:已知X Y,所以先求[X]补, [-Y]补 ,便求得[X-Y]补。然后在求X-Y。
也就是说,上一题已知的是[X]补 [Y]补,(机器的)运算结果是[X-Y]补。中间过程没必要求出X Y是什么数。
本题已知的是X Y,先得出机器的运算结果[X-Y]补,在做编译器的工作由[X-Y]补 求出X-Y。
二者求[-Y]补的方法不一样:前者是由-[Y]补 求得的,后者是先求-Y,然后求[-Y]补。
可以说,后面例子是编译器和系统共同工作的过程,前面例子只关系系统运算。
二.那么系统是怎么识别有符号数和无符号数的呢?
(1)CPU只会根据输入信号进行逻辑运算,在硬件级别是没有有符号无符号的概念,运算结束会根据运算前的信号和输出信号来设置一些标志位,是不是有符号由写程序的人决定,标志位要看你把操作数当有符号还是无符号来选择,就像内存中的数据,你可以按照需要来解析,原始数据在那里,你要按什么数据格式来解析在于自 己的选择;
在汇编语言层面,声明变量的时候,没有 signed 和 unsignde 之分,汇编器统统将你输入的整数字面量当作有符号数处理成补码存入到计算机中,只有这一个标准!;
(2)
计算机对有符号整数的表示只 采取一套编码方式,不存在正数用原码,负数用补码这用两套编码之说,大多数计算机内部的有符号整数都是用补码,就是说无论正负,这个计算机内部只用补码来 编码!!!只不过正数和0的补码跟他原码在形式上相同,负数的补码在形式上与其绝对值的原码取反加一相同。
(3)
有符号数和无符号数在计算机里表示都是一样的,二进制的补码形式。
是有符号还是无符号,是编译器来辨认的。
例如:
unsigned char uch, char ch;
在内存中有个数0b11111111.
把它赋给uch,那么uch就是127
如果赋给ch,那么ch就是-1