计算机的算数运算 知识梳理

一、概要

揭示实数的表示方法、算术的算法、实现这些算法的硬件以及如何在指令中表示相关的内容。以及如何使用该计数加速算术运算密集型程序的运行

二、加法和减法

加减法:数据从右向左逐位相加,同时进位也相应的向左传播,减法可通过将减数在简单的取反之后再进行加法操作,通过加法来实现。

例:7-6,可直接通过原码的减法进行操作,或者通过7加上-6的二进制补码来实现

7-6=[0000 0111]原-[0000 0110]原=[0000 0001]原=1
7+(-6)=[0000 0111]原+[1111 1010]补=[0000 0001]=1

溢出:

硬件规模有限,若字宽只有32位,运算结果超出32位就会溢出。

二进制补码操作的溢出:对加法,正数和负数相加时,和必然小于任意一个操作数的绝对值,不会溢出。做减法时,源操作数符号相同,不会发生溢出。加或减两个32位的数可能产生需要33位来表示的结果,溢出发生时符号位被数值位占用而产生错位。当两个正数相加结果为负,即计算过程中发生了向符号位的进位操作,说明发生了溢出,反之亦然。减法时:当一个正数减去一个负数得到一个负的结果,或一个负数减去一个正数得到一个正的结果,也意味着发生了借位占用了符号位,即溢出。

无符号整数:无符号数通常表述内存地址,这种情况下的溢出可以忽略。

MIPS采用两种类型的指令来处理哪些情况下忽略溢出,哪些情况下进行溢出的检测的问题:

  • 加法add,立即数加法addi,减法sub,这三条指令在溢出时产生异常
  • 无符号加法addu,立即数无符号加法addiu,无符号减法subu,三条指令在发生溢出时不会产生异常

三、乘法

第一个操作源为被乘数multiplicand,第二个操作源被称为乘数multiplier,最终的结果被称为积product。若忽略符号位,乘积等于两个操作数的位数之和,显然要处理溢出。乘法的基本原则:当乘数位为1 时,只需将被乘数复制到合适的位置,当为0时,将0放到合适的位置。

乘法硬件只是简单的移位和加法叠加。编译器甚至会用移位指令来代替乘数为2的幂次的乘法操作。通过使用更多硬件的方法、并行做加法操作来提高运算速度。

顺序的乘法算法和硬件

乘数被放置在32位乘数寄存器中,积初始化为0被放到64位的积寄存器中。被乘数在每步需要左移一位,因为它需要与前面的中间结果相加。32步之后,32位的被乘数将左移32位,所以需要用64位的寄存器存放被乘数,且初始化时被放到最低的32位上,最半部分初始化为0。每执行一步这个寄存器就左移一步,将被乘数与64位积寄存器中的中间结果对齐并累加到中间结果。步骤如下

  • 给乘积加上被乘数,将结果写入乘积寄存器,乘数的最低位决定被乘数是否被加到积寄存器上
  • 被乘数寄存器左移一位,即将被乘数左移
  • 乘数寄存器右移一位,给出了下一个迭代要用的乘数位

上面3个步骤重复执行32次获得积,若每步需一个时钟周期,完成两个32位数的相乘约需100个时钟周期;一般加减法出现的次数比乘法频繁5-100倍,所以多步乘法不会显著影响性能,但若一个慢速操作在程序中占据一定比重,也会限制程序的性能。

改进——并行化加速执行:

  • 当乘数位为1时,将乘数和被乘数进行移位,同时将被乘数和积相加。
  • 这时需保证:硬件测试的是乘数最右边的位,而且得到的是被乘数移位前的值。
  • 加法器和寄存器中有未使用的部分,可通过将加法器和寄存器的位长减半来进一步优化这个硬件结构
  • 当乘数为常数时,乘法也可用移位来替代,有短常数的乘法可替换为一系列的移位和加法,左移一位就是将一个数放大两倍,几乎每个编译器都将以2为底的指数乘法替换为移位来进行优化

有符号乘法

首先将乘数和被乘数都转化为正数,并记住原来的符号位,即可用上述最后的算法迭代31次,符号位不必参与运算,当符号不同时,积为负,对应符号位初始化为负。这里是使用32位数字来表示通常要处理的无限数字,移位步骤需要对有符号的乘积进行扩展。

更快速的乘法——摩尔定律

在乘法运算开始的时候通过检查乘数的32位,来判断被乘数是否被加上。即,为乘数的每一位提供一个32位的加法器,一个用来输入被乘数和一乘数位相与的结果,另一个是上一个加法器的输出。将每一个右边的加法器的输出作为左边加法器的输入,形成一个高32的加法器栈,将32个加法器组织成一个并行树,只需等待log2(32),即5次32位加法的时间,而不是32次加法的时间。另外,通过使用进位保留加法器,乘法的计算速度可以快于5次加法,易于应用于流水线设计执行,且可以同步支持多个乘法运算。

MIPS中的乘法

MIPS提供一对单独的32位寄存器来容纳64位的积,称为Hi和Lo.乘法mult和multu分别对应于有符号积和无符号积。需使用mflo(move from lo)指令来获取32位的整数积,MIPS汇编器为乘法生成了一条伪指令,使用三个通用的寄存器,用mflo和mfhi指令将积送入指定的寄存器。

MIPS乘法指令都忽略溢出,所以要由软件来检测是否因积过大而32位不够表示。对于multu指令,若Hi为0则无溢出(无符号乘积,高位为0);对于multi指令,若Hi为Lo的符号位则也无溢出(有符号位,最高位与未扩展部分相同)。可以使用指令mfhi(move from hi)将Hi的值移入一个通用寄存器来检测溢出。

四、除法

两个源操作数:被除数dividend和除数divisor,结果称为商quotient,第二结果称为余数remainder;被除数=商*除数+余数≡被除数/除数=商+余数;其中余数要小于除数。有时,使用除法仅仅是为了获得余数,而忽视商,即求余运算。

除法算法及其硬件结构

这里假设被除数和除数都为正,则商和余数也都为非负,除法的源操作数和两个结果都为32为宽,暂且忽略符号位。开始时,32位的商寄存器被设为0,将除数放置在64位除数寄存器的左半边,算法每次迭代将除数向右移一位,每次右移一位和被除数对齐。余数寄存器也是64位宽,被初始化为被除数。控制逻辑决定何时对除数和商寄存器进行移位以及何时将新值写入余数寄存器。具体步骤:

  • 从余数寄存器中减去除数寄存器中的内容,将结果放在余数寄存器中
  • 若结果为正,即,除数小于被除数,取商为1,即商寄存器左移,最低位设置为1
  • 若结果为负,则通过给余数寄存器加上除数寄存器的内容来恢复原值,结果放在余数寄存器,商同样左移,最低位设为0
  • 除数右移,再次迭代,重复33次
  • 迭代完成后,余数和商存放在以他们命名的寄存器中

检验余数的正负只需简单检测余数的符号位是0还是1即可,这个算法需要n+1步来获得适当的商和余数。通过将源操作数和商移位与减法同时进行来加速。寄存器和加法器有未用的部分,可勇敢将加法器和寄存器的位长减半来改进硬件结构。

改进版:只有余数寄存器是64位,除数寄存器和ALU位宽减半,余数进行左移。这个结构将商寄存器和余数寄存器的右半部分进行了拼接,余数是65位从而保证加法器的进位不会丢失。

有符号的除法

记住除数和被除数的符号,若两者符号相异,则商为负。设置余数的符号必须满足:被除数=除数*商+余数,若-(x/y)≠(-x)/y编程会面临更大的挑战,若不管除数和商和符号,保持被除数和余数的符号相同,就可以避免这种问题。所以,有符号除法算法在源操作数的符号相反时商为负,同时应使非零余数的符号和被除数的符号相同。

更快速的除法——摩尔定律

除法每次迭代前需要知道减法结果的符号,而乘法却可以立刻生成32个部分积,所以不可像乘法一样使用许多加速器来加速除法。但有一些计数如SRT的除法算法可以每步生成不止一个商位,通过查找表的方法来猜测每步几个商位,查找表基于被除数和余数的高位部分来进行,它依赖后面的部分来修正错误的猜测。

MIPS中的除法

除法和乘法有相同的硬件执行顺序。MIPS用32位的Hi和32位的Lo寄存器来处理乘法和除法。除法指令执行后,Hi存放余数,Lo存放商。有符号整数采用div,无符号整数采用divu,MIPS允许用三个寄存器采用mflo和mfhi将运算结果放入指定的通用寄存器中。MIPS处理除法指令忽略溢出,需要软件检验商是否溢出。除法还可能产生除数为0这样的错误运算,一些计算机会分辨这两种异常。MIPS需通过软件来判断检查除数是否发生此类错误。或者,在余数为负时,不需要立即将除数加回去,只是在下一步简单的讲除数加到移位后的余数上:(a+b)*2-b=a*2+b*2-b=a*2+b;前面的算法为恢复(restoring)算法,这里为不执行算法nonperforming,平均减少了三分之一的算术操作。

猜你喜欢

转载自www.cnblogs.com/yuanerduo/p/12543618.html
今日推荐