1、IA-32中的整数运算
- 整数加减法运算
内存中整形数是以补码的形式存储在内存中:
原码表示范围:负数部分:1111 1111(-127)~1000 0000(-0);正数部分:0000 0000(+0)~01111111(127)
补码表示范围:负数部分:1000 0001(-127)~11111111(-1);正数部分:0000 0000(+0)~0111 1111(127)
其中,原码中的1000 0000(-0)用来表示补码中的最小负数1000 0000(-128),所以补码相比于原码多表示一个最小负数。
逻辑电路中的加法器实现:
对于加法运算:
逻辑选择部件mux的输入SUB信号为0,CIN信号为0,选择B作为输出。
对于减法运算:
逻辑选择部件mux的输入SUB信号为1,CIN信号为1,选择非B作为输出。
标志位:
OF = Cn xor Cn-1
SF = Fn-1
CF = CIN xor Cn
ZF = F0 and F1 ~Fn-1
整数加减法的溢出:
无符号加溢出条件:最高位进位,数值超出表示范围,即CF =1;带符号加法溢出条件:两个正数相加结果为负,即OF =1。
无符号减溢出条件:CF =1;带符号减溢出条件:OF =1。
程序中的溢出判断:
- 整数乘法运算
高级语言中两个正数相称得到的结果通常也是一个n为整数,所以结果只取低n位
C语言编程中计算:
int z = x * y
其中汇编上述指令转换为机器码后,在乘法运算电路中得到的乘积是64位,但是高级语言只取低32位赋值
乘法运算的溢出判断:
无符号数乘积:若高位全0,则不溢出,否则溢出
带符号数乘积:若高位全0或全1且等于低n位的最高位,则不溢出,否则溢出
对于汇编语言,也就是计算机指令,乘法指令不置标志位,也就是不通过标志位来判断乘法是否溢出。所以要通过2n为乘积来判断溢出。
汇编语言中,乘法指令分为无符号乘指令、带符号乘指令。
整数乘法运算相比移位与加法运算所用时间长,通常一次乘法运算需要多个时钟周期,而一次移位、加法运算和减法运算只要一个或者更少的时钟周期,因此编译器在处理变量与常数相乘是,往往以移位、加法和减法的组合来替代乘法运算。
不管是无符号还是带符号整数乘法,即使乘积溢出时,利用移位和加减法运算组合的方式带到的结果都是和采用直接相乘的结果是一样的。
例:表达式 x*20 除了可以利用乘法器来运算外,还可以通过移位器和加法器来运算:
x * ( 2^4 + 2^2) = x << 4 + x << 2
- 整数除法运算
对于整数除法,因为商的绝对值不可能比被除数的绝对值大,因而不会发生溢出,也就是不会像整数乘法那样发生整数溢出漏洞。除了一个例外:
-2^(n-1)/-1 = 2^(n-1) 用补码最小负数除以-1,结果为2^(n-1),超出nbit数的最大表示范围。
除法运算的舍如规则:
整数除法中,商也是整数,所以在不能进行整除是需要进行舍入,通常按照超0的方向舍如,也就是整数商取比自己小的整数,负数商取比自己大的整数。
对于整数除法运算,由于计算机中除法运算比较复杂而且不能用流水线实现,所以一次除法运算大致需要30个或更多个时钟周期,比乘法指令的时间还长。
编译器在处理一个变量与一个2的幂次形式的整数相处时,常采用右移和算法数加减的运算来实现
无符号:逻辑右移
带符号:算数右移(逻辑移位+补符号位)
2、浮点数运算
计算机中浮点数采用IEEE 754 标准规定的形式存储在内存中。
1位符号位,8位阶码(移码表示,偏置常数为128),23位尾数(原码表示,第一位默认1不明显表示,所以可以表示24位尾数)
对于64位的双精度浮点数(double):
1位符号位,11位阶码,52位尾数
只用低80bit来表示浮点数,高12位无意义
我们用单精度浮点数来说明问题:在浮点数中,0也存在浮点数的表示形式:
浮点数+0:符号位为0,阶码和尾数全为0;
浮点数-0:符号位为1,阶码和尾数全为0。
相比于整形数,浮点数还可以表示正无穷和负无穷:
需要特别说明的是:浮点数除以0的结果 +/-无穷,而不是溢出异常(整数除0为异常)。
正无穷:符号位为0,阶码全为1,尾数全为0;
负无穷:符号位为1,阶码全为1,尾数全为0。
浮点数的中的“非数”表示:阶码全为1,尾数不全为0
阶码上溢:阶码超出了最大表示范围,阶码全为1,表示正/负无穷数
阶码下溢:阶码超出了最小表示范围,阶码全为0,表示+/-0
浮点数加减运算:浮点数在内存中右符号位、阶码、尾数组成,其中阶码表示浮点数的表示范围,尾数表示浮点数的表示精度。在浮点数加减运算,在进行对阶操作后,直接对两个操作数进行加减运算。
尾数加法:在尾数原码的基础上直接相加;
尾数减法:在尾数原码的基础上,被减数B取反经过二选一选择器传入加法器,SUB也就是CIN信号传入1参与计算。