3.1引言
3.2 加法和减法
- 硬件规模总是有一定限制的,如字宽只有32位,当运算结果超过这个限制时,就会发生溢出。
- 一般来说,对于有符号数,当相加的两个源操作数符号相异时,不会发生溢出;当相减的源操作数的符号相同时,不会发生溢出。对于无符号数,通常用来表示内存地址,这种情况下的溢出可以忽略。
MIPS采用两种类型的算术指令来解决这个问题:
- 加法(add)、立即数加法(addi)、减法(sub),这三条指令在溢出时产生异常;
- 无符号加法(addu)、立即数无符号加法(addiu)、无符号减法(subu),这三条指令在溢出时不会产生异常。
- 从本质上说,异常或中断是一种打断正常过程的系统调用。异常:一种打断正常过程执行过程的事件;中断:来自处理器外部的异常。
- 产生溢出的指令地址保存在一个寄存器中,而后计算机会跳到一个预先设定好的地址去执行相应的异常处理程序。保存异常地址的目的是为了在某些条件下能够在异常处理程序执行完后返回原程序继续执行。
3.3 乘法
- 积的位数一般远远大于被乘数和乘数,事实上,如果忽略符号位,若被乘数为n位,乘数为m位,则积的位数为n+m。即需要n+m位来表示所有可能的积。
- 核心思想:对于乘法,当乘数位为1时,只需要将被乘数复制到合适的位置;当乘数位为0时,将0放置到合适的位置。
3.3.1 顺序的乘法算法和硬件
-
假设乘数放置在32位的乘数寄存器中,64位的积寄存器被初始化为0.从采用纸和笔计算的方法中,我们可以清楚地看到被乘数在每步需要左移一位,因为它需要与前面的中间结果相加。在经过32步后,32位长的被乘数将要左移32位。因此,我们还需要一个64位的被乘数寄存器,且在初始化时32位的被乘数放在右半部分,左半部分清0。然后,每执行一步,这个寄存器中的值就左移一位,将被乘数与64位积寄存器中的中乘数的最低位(乘数的第0位)决定了被乘数是否被加到积寄存器上。第二步中的左移起着将被乘数左移的作用,就如同用纸和笔做乘法一样。第三步中的右移给出了下一个迭代中要用的乘数位。这三个步骤要重复执行32次来获得积。乘数的最低位(乘数的第0位)决定了被乘数是否被加到积寄存器上。第二步中的左移起着将被乘数左移的作用,就如同用纸和笔做乘法一样。第三步中的右移给出了下一个迭代中要用的乘数位。这三个步骤要重复执行32次来获得积。
-
乘数的最低位(乘数的第0位)决定了被乘数是否被加到积寄存器上。第二步中的左移起着将被乘数左移的作用,就如同用纸和笔做乘法一样。第三步中的右移给出了下一个迭代中要用的乘数位。这三个步骤要重复执行32次来获得积。
改进版
3.3.2 有符号乘法
- 当处理有符号乘法时,首先将被乘数和乘数转化为正数,并记住原来的符号位,当上述最后的算法迭代31次后,符号位不必参与运算。当符号相异时,积为负。
3.3.3 更快速地乘法
- 主要思想是为乘数的每一位提供一个32位的加法器。
3.3.4 MIPS中的乘法
- MIPS提供了一对单独的32位寄存器来容纳63位的乘积,称为Hi和Lo;
- 为了产生正确的有符号积和无符号积,MIPS提供了两条指令:乘法(mult)和无符号乘法(multu);
- 为了取得32位的整数积,程序员需要使用mflo指令。
3.4 除法
- 除法用的较少,但会出现数学上的无效操作:除数为0;
-
核心思想:除法运算的过程中每次都尝试看最大能减掉多少,然后以此产生商。从而很容易判断出需要将多少倍的除数从被除数中减去:要么是1倍,要么是0倍。二进制数仅包含0和1,所以二进制除法也仅有这两种选择,从而简化了二进制除法。
3.4.1 除法及其硬件结构
-
计算机不可能提前知道除数是否小于被除数,所以需要在第1步中减去除数这与在小于时设置指令中的比较操作相同;如果结果为正,则除数小于等于被除数,所以我们取商为1。如果结果为负,则通过将除数加上余数来恢复上一次的值,然后取商为0。除数右移,然后再次迭代。迭代完成后,余数和商存放在以它们命名的寄存器中。
3.4.2 有符号除法
- 对于有符号除法,记住除数与被除数的符号,如果两者的符号相异,则商为负。
3.4.3 更快速地除法
3.4.4 MIPS中的除法
- MIPS提供了一对单独的32位寄存器来容纳63位的商,称为Hi和Lo;
- 为了产生正确的有符号商和无符号商,MIPS提供了两条指令:除法(mult)和无符号除法(multu);
3.5 浮点运算
- 科学计数法:十进制小数点左边只有一位整数的计数法;规格化数:没有前导0且小数点左边只有一位整数的浮点计数法。
3.5.1 浮点表示
- 尾数(fraction):位于浮点数和尾数字段,其值在 0 和 1 之间。
- 指数(exponent):位于浮点数的指数字段,表示小数点的位置。
- 考虑到字的大小是固定的,浮点表示的设计者必须在尾数位宽和指数位宽之间找出折中的办法。浮点数通常是多个字的宽度,MIPS中,s为浮点数的符号(1表示负数),指数域为8位宽(包括指数的符号位),尾数域为23位宽,这种表示成为符号和数值(sign and magnitude), 因为符号和数值的位置是相互分离的。
一般浮点数的表示形式:
其中F为小数域的值,E为指数域的值。
- 上溢(overflow):正的指数太大而导致指数域放不下的情况。
- 下溢(underflow)):负的指数太大而导致指数域放不下的情况。
- 一种减少上溢和下溢的方法:采用更达的指数格式。C语言中成为double,基于double的操作成为双精度(double precision)浮点算术,指的是浮点数由两个32位的字表示。单精度(single precision)浮点就是前面的格式,指的是浮点数由一个32位的字表示。
IEEE 754 浮点标准: 双精度浮点数占用了两个MIPS字,如下所示。其中,s表示符号,指数域为11位,尾数与为52位。
它的主要的优势还是通过提供更多的有效位数来实现更达的表示精度。
- 为了将更多的数据为打包到有效位数(significand)部分,IEEE 754 标注甚至隐藏了规格化二进制数的前导位 1 . 因此,在单精度浮点数下,数有24位宽(隐含的规格化二进制数的前导位1和23位尾数);在双精度的情况下,数有523位宽(1+52)。为了精确,我们用术语有效位数来表示24位或者53位的数,就是隐含1加上位数。 因为 0 没有前导位 1 ,它的指数保留为0,所以硬件就不会将前导位1 加到尾数上。其余的数使用前面的形式
其中F为 0 和 1 之间的数。 准确而言是
其中,无穷用来处理 除0中断;非数字用来推迟程序中的一些测试和决定。
- 为什么符号位放在最前面?因为 IEEE 754的设计者希望浮点能够比较快速地处理整数比较。
- 为什么将指数放在有效位数前?因为这样可以简化用整数比较指令来处理地浮点数分类,有着相同符号的情况下,指数越大数值越大。
带偏阶的计数法(biased notation):在IEEE 754中单精度的偏阶为 127,双精度的指数偏阶为 1023。带上偏阶之后,浮点数的表示为:
3.5.2 浮点加法
浮点加的基本结构:
-
每步从顶向下对应到每个方框。首先,使用一个小的ALU将两个指数相减来决定哪个指数大及大多少。指数差将控制三个多路复用器;从左到右,选择出较大的指数、较小数的有效数和较大数的有效数。较小数的有效数通过右移后,和较大数的有效数用一个大的ALU相加。规格化步骤将和左移或者右移,同时增加或者减少指数。舍入产生最后的结果,这样也有可能需要再次规格化,然后产生最后的结果
3.5.3 浮点乘法
3.5.4 MIPS中的浮点指令
3.6 并行性和计算机算术
-
通过在128位内对进位链进行分割,处理器可以同时对16个8位、8个16位、4个32位或2个64位的运算同时进行并行操作。对加法器进行这样的分割的开销非常小。将这种在一个宽字内部进行的并行操作称为子字并行,也可将其称为更加通用的数据级并行。它们也被称为向量或SIMD(单指令多数据)。多媒体应用的日益广泛促使支持易于并行实现窄位宽操作的算术运算指令的出现。