1
0
mirror of https://github.com/Didnelpsun/CS408.git synced 2026-02-08 05:14:48 +08:00
Files
CS408/Computer-Organization/1-data-representation-and-operation.md
Didnelpsun c3acb94b94 更新
2022-10-17 22:48:20 +08:00

58 KiB
Raw Permalink Blame History

数据表示与运算

数制与编码

进位计数制

  • 真值:符合人类习惯的数字。
  • 机器数:数字实际存到机器里的形式,正负号需要被“数字化”。

十进制

  • 符号反映权重。
  • 符号所在位置也反映权重。
  • $K_nK_{n-1}\cdots K_2K_1K_0K_{-1}K_{-2}\cdots K_{-m}=K_n\times10^n+K_{n-1}\times10^{n-1}\cdots K_2\times10^2+K_1\times10^1+K_0\times10^0+K_{-1}\times10^{-1}+K_{-2}\times10^{-2}\cdots K_{-m}\times10^{-m}$。

R进制

  • 基数:每个数码位所用到的不同符号的个数,$r$进制的基数$r$。
  • $R$进制转换为十进制:$K_nK_{n-1}\cdots K_2K_1K_0K_{-1}K_{-2}\cdots K_{-m}=K_n\times r^n+K_{n-1}\times r^{n-1}\cdots K_2\times r^2+K_1\times r^1+K_0\times r^0+K_{-1}\times r^{-1}+K_{-2}\times r^{-2}\cdots K_{-m}\times r^{-m}=\sum_{i=-m}^nK_i\times r^i$。
  • 二进制:$0$、$1$。
  • 使用二进制的原因:
    1. 可使用两个稳定状态的物理器件表示。
    2. $0$$1$正好对应逻辑值假、真。方便实现逻辑运算。
    3. 可很方便地使用逻辑门电路实现算术运算。(物理部件性质决定)
  • 八进制:$0\sim7$。可以用下标方式表明,也可以用结束的$O$或开头的$0$表示。如$(1643)_8$、$01643$、$1643O$。
  • 十进制:$0\sim9$。可以用下标方式表明,也可以用结束的$D$表示,如$(1643)_{10}$、$1643D$。
  • 十六进制:$0\sim9$、$A$、$B$、$C$、$D$、$E$、$F$。可以用下标方式表明,也可以用结束的$H$或开头的$0x$表示。如$(1643)_{16}$、$0x1643$、$1643H$。

二进制与八进制或十六进制转换

  • 二进制转换八进制:三位一组,每组转换成对应的八进制符号,整数部分不全则最高位用$0$填充,小数部分不全则最低位用$0$填充。
  • 二进制转换十六进制:四位一组,每组转换成对应的十六进制符号,整数部分不全则最高位用$0$填充,小数部分不全则最低位用$0$填充。
  • 八进制转换二进制:每位八进制对应的三位二进制。
  • 十六进制转换二进制:每位十六进制对应的四位二进制。
十进制 二进制 八进制 十六进制
0 0000 0 0
1 0001 1 1
2 0010 2 2
3 0011 3 3
4 0100 4 4
5 0101 5 5
6 0110 6 6
7 0111 7 7
8 1000 10 8
9 1001 11 9
10 1010 12 A
11 1011 13 B
12 1100 14 C
13 1101 15 D
14 1110 16 E
15 1111 17 F

十进制转换为R进制

  • 整数部分需要使用除基取余法,小数部分需要使用乘基取整法。
  • 对于十进制数,需要把它分为整数部分和小数部分两个部分进行处理。
  • 已知$R$进制转换为十进制的方法:$K=K_nK_{n-1}\cdots K_2K_1K_0K_{-1}K_{-2}\cdots K_{-m}=K_n\times r^n+K_{n-1}\times r^{n-1}\cdots K_2\times r^2+K_1\times r^1+K_0\times r^0+K_{-1}\times r^{-1}+K_{-2}\times r^{-2}\cdots K_{-m}\times r^{-m}$。
  • 分为整数部分和小数部分:$K=N+F$。
  • 首先把整数拿出来得到$N=K_n\times r^n+K_{n-1}\times r^{n-1}\cdots K_2\times r^2+K_1\times r^1+K_0\times r^0$。
  • 对这个数除以基数$r$,得到$X=K_n\times r^{n-1}+K_{n-1}\times r^{n-2}\cdots K_2\times r^1+K_1\times r^0$,这时候就会得到一个余数$K_0$。所以$N=rX+K_0$,这时候就能算出$K_0$这个位数了。
  • 同理再将得到的商$X$同样除以$r$,就能得到$K_1$,所以不断递归就会得到整数部分所有的$K_i$。商为$0$时结束。
  • 得到的$K_i$是从低位排到高位。
  • 对于小数部分$F=K_{-1}\times r^{-1}+K_{-2}\times r^{-2}\cdots K_{-m}\times r^{-m}$。
  • 对这个数乘基数$r$,得到$K_{-1}\times r^0+K_{-2}\times r^{-1}\cdots K_{-m}\times r^{-m+1}$,取这个常数$K_{-1}$就是想要的答案。将乘积减去这个整数部分得到后面处理的数据
  • 同理再将得到的数据不断乘基数,就能得到小数部分所有的$K_i$。积为$1.0$时结束。
  • 得到的$K_i$是从高位排到低位。
  • 将整数和小数合在一起就是最后的结果。
  • 有时候小数会出现无法彻底转换的情况,需要考虑保留多少位。

基本上都是十进制转为二进制,然后由二进制转为十六进制或八进制,具体转换过程见例题。

同理也可以使用拼凑法将数字相减拼凑成对应的数值。这种方法对于只有整数的数值比较好用。

2^{12} 2^{11} 2^{10} 2^{9} 2^{8} 2^{7} 2^{6} 2^{5} 2^{4} 2^{3} 2^{2} 2^{1} 2^{0} 2^{-1} 2^{-2} 2^{-3}
4096 2048 1024 512 256 128 64 32 16 8 4 2 1 0.5 0.25 0.125

真值与机器数

使用正负号表示正负数的就是真值。

将数的符号和数值一起来编码的,如原码、反码、补码就是机器数。

BCD码

即$Binary-Coded,Decimal$,用二进制编码的十进制。

使用$4bit$来表示$0$到$9$这十个数,而$4bit$能表示十六个数,所以会冗余六个组合。

8421码

$8421$码是一种有权码,第$1$、$2$、$3$、$4$位分别对应$8$、$4$、$2$、$1$,使用常规的二进制来表示十进制,冗余最后六个:

0 1 2 3 4 5 6 7 8 9
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001

$8421$码就是二进制表达十进制,只不过十进制只进行简单的对照二进制并进行一位位的拼接,与真正的二进制和十六进制不同。如十六进制的$46H=$二进制的$0100,0110=$十进制的$38D=8421$码的$0011,1000$$985$用$8421$码表示就是$1001,1000,0101$。

使用$8421$码表示的数字进行算术运算的方式是先按照二进制的方式进行运算,若最后结果不在映射表中,即落在没有定义的$1010$到$1111$中,就直接加上$6$(因为有六位无效,所以加上六位跳过无效的位数)从而向前面一个数字段进一位加一,高位补全$0$。每个段对应的数值合在一起就是原来的结果。

如$5+8=0101+1000=1101=13$,不在映射表中,则对$1101$进行二进制的加$6D=0110$,即计算$1101+0110=1,0011$,补齐得到$0001,0011$,而按照$8421$码,最高位的$0001$不再代表权值$16$,而代表十位的$1$,而后面是$3$,从而组合在一起就代表了$13$。

余三码

在$8421$码的基础上全部加上三:

0 1 2 3 4 5 6 7 8 9
0011 0100 0101 0110 0111 1000 1001 1010 1011 1100

余三码因为加上了三,所以每一位的权值映射关系就破坏了,所以这是一种无权码,不能分别对应$8$、$4$、$2$、$1$的值。

2421码

与$8421$码一样都是一种有权码,但是映射的方式不同,第$1$、$2$、$3$、$4$位分别对应$2$、$4$、$2$、$1$。

0 1 2 3 4 5 6 7 8 9
0000 0001 0010 0011 0100 1011 1100 1101 1110 1111

字符与字符串

英文字符表示

$ASCII$码,数字英文符号一共$128$个字符,使用$7$位就可以表示$128$个字符,但是通常会高位补$0$凑足$1B$

  • 其中$32$到$126$是可印刷字符,其他都是控制或通信字符。
  • 数字:$48$$0011,0000$)到$57$$0011,1001$),后面$4$位就是数字的$8421$码。
  • 大写字母:$65$$0100,0001$)到$90$$0101,1010$),前面三位是$010$,后面五位代表$1$到$26$。
  • 小写字母:$97$$0110,0001$)到$122$$0111,1010$),前面三位是$011$,后面五位代表$1$到$26$。

中文字符表示

  • $GB,2312-80$$1980$年推出汉字加符号共$7445$个表示的字符。中文有两个字节。
  • 汉字编码包括汉字的输入编码、汉字内码、汉字字形码,用于输入、内部处理、输出。
    • 输入编码:如拼音、五笔等供人类输入,输入编码输入后转换为国标码再转成汉字内码存储。
      • 区位码:两个字节表示一个汉字,每字节用七位码,将汉字和符号排成$94$个区,每个区$94$位。四位十进制数,前两位是区码,后两位为位码。
      • 国标码:将十进制的区位码转换为十六进制。为了中文字符表示与英文字符表示共存,防止$GB$编码被认为是$ASCII$码的$0$到$32$位的控制或通信字符,所以在$94$区$94$位的基础上还要各自加上$32$,即$20H$,防止信息交换时冲突。国标码两字节最高位都是$0$。
    • 汉字内码:国标码只能用于信息传输,而如果是存储在计算机上,由于前$128$位已经被$ASCII$码占用了,所以在国标码的基础上再各自加$80H$$128$),从而计算机识别字符时,看到$0$到$128$之间的就能辨认出是$ASCII$码,大于$128$的就是$GB$码。因为$ASCII$码高位是$0$,而$GB$码是两个字节且高位都是$1$。
      • 国标码=区位码$H$+$2020H$。
      • 汉字内码=国标码$H$+$8080H$。
    • 汉字字形码:把汉字输出成汉字的样子。

字符串

  • 若一个计算机按字节编址,则每个地址对应$1B$。
  • 很多语言中将$'\backslash0'$即$00H$作为字符串结束标志。
  • 大端模式:将数据的最高有效字节存放在低地址单元中。
  • 小端模式:将数据的最高有效字节存放在高地址单元中。
  • 计算机默认是小端模式,人类常用书写方式是大端模式。

数据校验

现在计算机组成原理不考数据校验,但是只是内容移动到计算机网络里。具体可以看计算机网络。

  • 校验原理就是将更多字节映射到有限个合法状态,从而有多个冗余的非法状态,更容易判断是否非法。
  • 码字:由若干位代码组成的一个字。
  • 两个码字间的距离:将两个码字逐位进行对比,具有不同的位的个数。
  • 码距:一种编码方案可能有若干个合法码字,即为各任意合法码字间最少变化的二进制最小位数。(如$1000$与$1001$码距为$1$$1111$码距为$3$

纠错理论

当码距$=1$时,无检错能力;当码距$=2$时,有检错能力;当码距$\geqslant3$时,若设计合理,可能具有检错、纠错能力。

$L-1=D+C$且$D\geqslant C$。即编码最小码距$L$越大,其检测错误的位数$D$越大,纠正错误的位数$C$也越大,且纠错能力恒小于等于检错能力。

奇偶校验码

即通过在数据上添加一位校验位让所有数据为$1$的位的个数为奇数或偶数。

  • 奇校验:让整个校验码(有效信息位加上校验位)中为$1$的个数为奇数。
  • 偶校验:让整个校验码(有效信息位加上校验位)中为$1$的个数为偶数。
  • 偶数个位数出错时无法校验。
  • 对原始数据进行异或(模二加)运算,得到的结果即为校验位。
  • 对所有数据进行异或运算,结果为$0$表示未出错,为$1$代表出错。
  • 码距为$2$,只能检错,不能纠错。(为$1$的位数的个数为偶数或奇数,偶数和偶数,奇数和奇数之间最小差距为$2$,所以码距为$2$

海明码

  • 将信息分组进行偶校验,从而得到多个校验位,从而能携带多种状态信息。
  • 设信息位为$n$,校验位为$k$,从而校验位能表达$2^k$种状态,而传输总数据位数=信息位+校验位一共$n+k$位,只错一位的状态种数加上一种正确状态为$n+k+1$,从而$2^k\geqslant n+k+1$。
  • 令信息位为$D_i$,校验位为$P_j$,总海明码为$H_k$,其中校验位$P_j$必须放在海明码$H_k$位号位$2^{j-1}$的位置上,即$1$、$2$、$4$、$8$等。
  • 如果没有发生错误,则每一位进行检错都是$0$,若出现$1$,则说明出错。
  • 为了检测是一位错还是两位错,一般会加上一个全校验位,对整体进行偶校验。
  • 具有一位的纠错和两位的检错能力,三位以上则不能检错。
n 1 2-4 5-11 12-26 27-57 58-120
k 2 3 4 5 6 7

循环冗余校验码

  • 即$CRC$码,其思想是:
    1. 数据发送、接受方约定一个“除数”生成多项式$G(x)$。$R$为$G(x)$位数减一。
    2. $K$个信息位+$R$个校验位作为“被除数”,添加校验位后需保证除法的余数为$0$。
    3. 收到数据后,进行除法检查余数是否为$0$。
  • 得到$CRC$码的方法:
    1. 确定$K$和$R$以及生成多项式对应的二进制码。其中$R$位生成多项式的最高次幂数。
    2. 将信息码左移$R$位,低位补$0$。
    3. 使用模二除法。(即相减时是异或运算,不能向上进位或借位;除法取余数时也不比较除数与被除数除第一位以外的低位大小,只需要相同的位数,这是由于异或加减法不进行进借位的特征)
    4. 余数就是校验位,只比多项式少一位。
    5. 对全部数据进行多项式除,余数为$0$代表无错。
    6. 若余数不为$0$,则出错。
    7. 若$n$个信息位,$k$个校验位,若生成多项式得当,且$2^k\geqslant n+k+1$,则$CRC$码可纠正一位错。实际上基本上不怎么用来纠错。
  • 检错:将收到的$CRC$码用生成多项式$G(x)$做模二除法,若除数为$0$则码字无误,若只有一位为$1$,则该位出错,直接取反,更多位则无法检错。即只具有一位的检错纠错能力。

定点数

指小数点的位置不变,使用常规计数法,如$96.94$。

定点数表示

无符号数

  • 整个机器字长的全部二进制位均为数值位,没有符号位,相当于数的绝对值。
  • $n$位无符号数表示范围为$[0,2^n-1]$。
  • 无符号数不涉及小数。
  • 无符号数只有原码的概念,没有反码、补码、移码。

有符号数

  • 假设机器字长$n+1$位,符号位$1$位,有效数字位$n$位。
  • 定点整数:最高一位是符号位,$0$是正,$1$是负,小数点位置一般隐含在最后。范围为$[-(2^n-1),2^n-1]$。
  • 定点小数:最高一位是符号位,$0$是正,$1$是负,小数点位置隐含在符号位后面,是纯小数。范围为$[-(1-2^{-n}),-2^{-n}]\cup[2^{-n},1-2^{-n}]$。
  • 数值部分也称为尾数。要保存一个非整数需要保存定点整数与定点小数两个部分。

原码

  • 原码:用尾数表示真值的绝对值,符号位“$0/1$”对应“正/负”。
  • 若机器字长为$n+1$位,则尾数占$n$位。
  • 若使用$1B$来保存数值,则$+19D$就是$0001,0011$$-19D$就是$1001,0011$。
  • 有时$1001,0011$会写为$1,0010011$,其中的逗号只是为了标注正负号,本身是不存在的。
  • 若未指明机器字长,则最开头的多个$0$可以省略。如$1001,0011$可以表示为$1,10011$。
  • 同理小数也可以使用$1.11$表示,这是指$-0.11$而不是真值$1.11$。
  • 若机器字长$n+1$位,则原码整数的表示范围是$[-(2^n-1),2^n-1]$。
  • 若机器字长$n+1$位,则原码小数的表示范围是$[-(1-2^{-n}),-2^{-n}]\cup[2^{-n},1-2^{-n}]$。
  • 原码表示时真值$0$有$+0$和$-0$两种形式,因为符号位对$0$没有影响,所以造成了一定的空间浪费和错乱。

反码

  • 反码:若符号位为$0$,则反码与原码相同,若符号位为$1$,则数值位全部取反。
  • 可以转换为原码再取反。
  • 若机器字长$n+1$位,则反码整数的表示范围是$[-(2^n-1),2^n-1]$。
  • 若机器字长$n+1$位,则反码小数的表示范围是$[-(1-2^{-n}),-2^{-n}]\cup[2^{-n},1-2^{-n}]$。
  • 范围表示没有变化。
  • 反码表示时真值$0$有$+0$和$-0$两种形式。
  • 反码只是由原码转换为补码的一个中间态,实际上并没有作用。

补码

  • 补码:若符号位为$0$,则反码与原码相同,若符号位为$1$,则数值位全部取反再加一,即反码加一。
  • 补码表示时真值$0$只有一种形式$0000,0000$。
  • 多出来的一种形式$1000,0000$表示正数的$-2^7$和小数的$-1$。
  • 若机器字长$n+1$位,则补码整数的表示范围是$[-2^n,2^n-1]$。(比原码多个$-128$
  • 若机器字长$n+1$位,则补码小数的表示范围是$[-1,1-2^{-n}]$。(比原码多个$-1$
  • 负数补码转回原码:尾数取反,末位加一;或是负数补码中,最右边的$1$以及右边不变,最右边的$1$的左边取反。
  • 数值的补码求其负数的补码:全部位包括符号位取反,末位加一。
  • 对一个整数的补码再求补码,等于该整数自身。
  • 补码算术移位:将补码的符号位与数值位一起右移一位并保持原符号位的值不变,表示除二。
  • 变形补码:又称为模四补码,即双符号位的补码小数,用$00$表示正,$11$表示负,用于完成算术运算的$ALU$部件中。

移码

  • 一般是在补码的基础上只将符号位取反,即在真值上加上一个常数偏移量$2^n$。也可能加上不同的偏移量。
  • 移码只能用于表示整数,而不能表示定点小数。一般用来表示浮点数的阶码。
  • 若机器字长$n+1$位,则移码整数的表示范围是$[-2^n,2^n-1]$。
  • 若机器字长$n+1$位,则移码小数的表示范围是$[-1,1-2^{-n}]$。
  • 只有一个零的表示$10\cdots0$。
  • 移码由于负数的最高位为$0$,正数的最高位为$1$,所以保证了原数据大小顺序,从而能更方便对比大小。
机器数 无符号数 原码 反码 补码 移码
0000 0000 0 +0 +0 0 -128
0000 0001 1 +1 +1 +1 -127
...
0111 1101 125 +125 +125 +125 -3
0111 1110 126 +126 +126 +126 -2
0111 1111 127 +127 +127 +127 -1
1000 0000 128 -0 -127 -128 0
1000 0001 129 -1 -126 -127 1
1000 0010 130 -2 -125 -126 2
...
1111 1101 253 -125 -2 -3 125
1111 1110 254 -126 -1 -2 126
1111 1111 255 -127 -0 -1 127

补码作用

  • 原码在计算时由于首位表示的是符号,所以需要考虑将加减运算转换的问题,而减法实现起来比较困难,就考虑是否可以将减法通过加法来实现。
  • 由于计算机码操作若最高位进一就被舍弃,则天然是进行模运算,所以可以通过数学模运算来实现机器码的运算。
  • 带余除法:设$x,m\in Z$$m>0$则存在唯一决定的整数$q$和$r$,使得$x=q\cdot m+r,,0\leqslant r<m$。
  • 若两个数绝对值之和为模,则互为补数。即模-数的绝对值=数的补数(正数)。从而数加上数的补数就得到了模。
  • 补码就是正数不变,负数取模的结果。如$-66=-0100,0010$,而$(1000,0000-0100,0010)\mod(1111,1111)=1011,1110$,也就是其补码。
  • 从而就可以用补数的加法(被减数转为其负数的补码)替代原码转换的加减法。
  • 所以补码可以让减法操作转换为加法操作,减少硬件成本。

定点数运算

定点数移位运算

  • 算术移位:针对有符号数,符号位保持不变,通过改变各个数码位和小数点的相对位置,从而改变各数码位的位权。可用移位运算实现乘法、除法。
    • 原码的算数移位——仅对数值位进行移位:
      • 若右移高位补$0$,低位舍弃,右移代表除$2$,若移出的是$0$则刚好整除,若移出的是$1$则会整除余$1$丢失精度。
      • 若左移低位补$0$,高位舍弃,左移代表乘$2$,若移出的是$0$则刚好乘$2$,若移出的是$1$,则会溢出严重误差。
    • 反码的算术移位——正数的反码与原码相同,所以正数的处理跟原码一样。而对于负数而言,反码的$1$等于原码的$0$,反码的$0$等于原码的$1$
      • 若右移低位补$1$,高位舍弃。
      • 若左移高位补$1$,低位舍弃。
    • 补码的算术移位——正数的补码与原码相同,所以正数的处理跟原码一样。由于负数补码=反码末位加一,导致反码最右边几个连续的$1$都因进位而变为$0$,直到进位碰到第一个$0$为止。所以得到规律:
      • 负数补码中,最右边的$1$及其右边同原码一样。最右边的$1$的左边同反码一样。
      • 右移同反码,高位补$1$,低位舍弃。
      • 左移同原码,低位补$0$,高位舍弃。
  • 逻辑移位,逻辑的移位可以视为对无符号数的算术移位:
    • 逻辑右移:高位补$0$,低位舍弃。
    • 逻辑左移:低位补$0$,高位舍弃。
  • 循环移位,将移出的一位放到另一端的端点,类似队列:
    • 进位位$CF$:保存计算是否进位。$1$代表产生进位,$0$代表未产生进位。
    • 带$CF$就是大循环,不带$CF$的就是小循环。不论带不带$CF$进行循环移位,最高位的值都必定与$CF$的值相等。
    • 循环右移:将最低位的一位移出放到最高位,其余右移一位。
    • 循环左移:将最高位的一位移出放到最低位,其余左移一位。
    • 带进位位的循环左移:需要加上进位位数值的循环左移。
    • 带进位位的循环右移:需要加上进位位数值的循环右移。
    • 适合将数据的低字节数据和高字节数据互换。

定点数加减运算

  • 注意机器字长,若溢出则将溢出位丢弃。
  • 原码的加减,由加法器和减法器两个硬件来实现,因为最高位为符号位,所以不能直接进行加减,符号位要单独处理:
    • 原码的加法:
      • 正数+正数:绝对值做加法,结果为正数。
      • 负数+负数:绝对值做加法,结果为负数。
      • 正数+负数:绝对值大的减绝对值小的,符号同绝对值大的数。
    • 原码的减法,减数符号取反,转变为加法:
      • 正-负→正+正。
      • 负-正→负+负。
      • 正-正→正+负。
      • 负-负→负+正。
  • 补码的加减,由于减法器的硬件实现比较困难,所以原码的减法操作可以由补码来更简单实现,不用考虑符号位的问题,直接全部参与运算:
    • 参与运算的两个操作数均用补码表示。
    • 按二进制运算规则运算,逢二进一(与模二加减法不同需要进位)。
    • 符号位与数值位按同样规则一起参与运算,符号位运算产生的进位要丢掉,结果的符号位由运算得出。
    • 补码加减运算依据下面的公式进行。当参加运算的数是定点小数时,模$M=2$;当参加运算的数是定点整数时,模$M=2^{n+1}$。$[A+B]\text{补}=[A]\text{补}+[B]\text{补}$$\mod M$$[A-B]\text{补}=[A]\text{补}+[-B]\text{补}$$\mod M$)。
    • $\mod M$运算是为了将溢出位丢掉。也就是说,若做加法,则两数的补码直接相加;若做减法,则将被减数与减数的机器负数相加。
    • 补码运算的结果亦为补码。
  • 溢出判断,由于使用补码进行加减操作都会变成加法,所以只用考虑加法溢出的处理。
    • 小于最小值就是下溢。只有负数+负数才会下溢得到正数。如$-24-124=1110,1000+1000,0100=0110,1100=108$。
    • 大于最大值就是上溢。只有正数+正数才会上溢得到负数。如$15+124=0000,1111+0111,1100=1000,1011=-117$。
    • 对于小数,其绝对值小于等于$1$。
    • 方法一,采用一位符号位(模二补码),根据符号位判断:
      • 设$A$的符号为$A_s$$B$的符号为$B_s$,运算结果的符号为$S_s$。
      • 则溢出逻辑表达式为$V=A_sB_s\overline{S_s}+ \overline{A_s}\overline{B_s}S_s$(即$V=A_s&&B_s&&!(S_s)\mid\mid!(A_s)&&!(B_s)&&S_s$,前面判断下+溢,后面判断上溢)。
      • 若$V=0$,表示无溢出,若$V=1$,表示有溢出。
      • 由于只有操作数同号才能溢出,即判断标准为,两个操作数是否同号,结果符号是否与原操作数相同,这两个条件必须同时满足。
      • 如$-24-124=108$产生了溢出,$A_s=1$、$B_s=1$、$S_s=0$$V=A_sB_s\overline{S_s}+ \overline{A_s}\overline{B_s}S_s=1,1,1+0,0,0=1+0=1$,所以产生了溢出。
    • 方法二,采用一位符号位(模二补码),根据数据位进位$1$情况判断:
      • 符号位的进位$C_s=0$,最高数值位的进位$C_1=1$时产生了上溢。
      • 符号位的进位$C_s=1$,最高数值位的进位$C_1=0$时产生了下溢。
      • 原理同方法一类似,如果进位产生并符号与期待符号不同则发生溢出。
      • 如$-24-124=1110,1000+1000,0100=0110,1100$中符号位都为$1$相加结果为$0$,所以符号位进位,$C_s=1$,而最高数值位为$1+0=1$,没有进位,所以$C_1=0$,所以就产生了下溢。
    • 方法三,采用双符号位(模四补码),正数符号为$00$,负数符号为$11$。
      • 若两个符号位不同,则表示溢出,第一个符号位表示应该得到的符号位,第二个符号位代表实际得到的符号位。
      • 如$-24-124=11,110,1000+11,000,0100=10,110,1100=108$。下溢。
      • 如$15+124=00,000,1111+00,111,1100=01,000,1011=-117$。上溢。
      • 实际存储时只存储一个符号位,运算时会复制一个符号位。
  • 符号扩展:防止溢出的一个方法就是将短数据扩展为长数据,把数据全部拓展为等长。(正数补码全部补$0$,负数补码高位补$1$低位补$0$
    • 整数扩展,在原符号位和数值位中间添加新位,正数都填充$0$,对于负数:
      • 原码:扩展补$0$。
      • 反码:扩展补$1$。
      • 补码:扩展补$1$。
    • 小数扩展,在最后面添加新位,正数都填充$0$,对于负数:
      • 原码:扩展补$0$。
      • 反码:扩展补$1$。
      • 补码:扩展补$0$。

定点数乘法运算

二进制乘法运算可以参考十进制的乘法运算,将乘数一位一位的乘被乘数然后再全部错位相加得到的就是答案。

  318
× 211
-------
  318
 318
636
-------
67098

为什么要错位?因为乘数每一位的数值的位权不同,为基数的幂,所以本质应该是:

        318
×(200+10+1)
-----------
        318
       3180
      63600
-----------
      67098

而使用二进制的一位位乘法显然比十进制的一位位乘更简单:

    1101
×   1011
--------
    1101
   1101
  0000
 1101
--------
10001111

所以此时分析笔算二进制乘法就被拆解出了二进制乘法流程:将乘法变为加法和移位运算,将乘数一位位的向前移动并与被乘数相乘,由于是二进制所以只有$0$和$1$,遇到乘数当前位值为$1$就在原来的和上加上被乘数,并向前移动一位,如果是$0$就加上$0$继续移动一位,当乘数位数访问完成则乘法完成,所有的和相加成为最后的积。

这就是原码乘法的原理,可以考虑用机器实现,但是还是要考虑以下问题:如何处理符号?乘积位数扩大一倍是否可能超过机器字长?各个位积如何相加变成最后的乘积?

原码一位乘法:

  • 一般使用原码一位乘法,即每次只乘一位的数据。
  • 在原码乘法时,可以先符号位单独处理,将两个符号进行异或操作,得到的结果就是最后的结果的符号。然后对数据的绝对值(去除符号位)进行一位位的乘法(位积)然后相加。
  • 由于运算时可能存在绝对值大于$1$但是不是溢出的情况,所以部分积和被乘数使用双符号位。
  • 在运算器的组成时出现一个表格,说明在进行乘运算时,$ACC$保存乘积高位,$MQ$保存乘数与乘积低位,$X$保存被乘数。
  • 原码一位乘法机器实现时就是按照这种方式计算:
    1. 字长若为$n+1$位,则$ACC$、$MQ$、$X$全部初始化为$n$位,将被乘数的绝对值放入$X$中,$MQ$放入乘数的绝对值,$ACC$初始化为全$0$。
    2. 将$MQ$的最右边的一位当做当前乘运算位,让其进行乘运算,运算规则是,若当前位是$1$,则$ACC$加上被乘数,即$ACC+=X$,若当前位是$0$,则$ACC$加上$0$(保持不变,跳过)。
    3. 将$ACC$和$MQ$的数据连接在一起,全部逻辑右移一位,$ACC$数据高位补$0$$ACC$最后一个低位移到$MQ$的最高位。将$MQ$的最后一位抛弃。若是第i轮逻辑右移则$MQ$的前$i$位是结果的后$i$个低位值。
    4. 从步骤二开始重复,字长若为$n+1$位,则重复$n$次,直到$MQ$的最后一位是符号位,则停止计算。此时$ACC$的全部和$MQ$的前$n$位都是结果。
    5. 定点小数的小数位隐藏在符号位后面第一位,定点正数的小数位隐藏在$MQ$符号位的前一位。
    6. 将两个符号位的异或结果赋值给积最高位。
  • 原码一位乘法逻辑运算:
    1. 初始化,左边为部分积,即计算的部分结果,最开始为全$0$,右边为乘数的绝对值,最后边全部为丢失位。
    2. 根据丢失位前一位的值来判断加上什么,若是$1$则加上被乘数的绝对值,若是$0$则加上被乘数等长的全$0$。
    3. 右移部分积一位,高位补$0$,丢失位多一位。
    4. 继续计算,直到乘数全部被移出。字长为$n+1$位则需要移位计算$n$次。丢失位前的就是全部部分积。
    5. 将两个符号位的异或结果赋值给积最高位。

补码一位乘法:

  • 对于补码的乘法运算的逻辑也跟原码的类似,补码的计算就是使用$Booth$算法实现。
  • 辅助位其实就是在$MQ$最后再加上一位,辅助位初始为$0$。每次右移会使$MQ$的最低位顶替原本的辅助位(事实上$MQ$共$n+2$位)。
  • 为了保证统一,所以$ACC$和$X$都会增加一位,变成$n+2$位,多出来的一位就可以实现双符号位补码运算,而$MQ$还是用原来的单符号位。
  • 为了加快运算会有辅助电路实现$(-x)$的补码的运算。
  • 最后一次不需要移位直接根据辅助位和$MQ$最后一位判断进行相加。从而让乘数的符号位也参数运算中来确定最后结果的符号。
  • 补码一位乘法逻辑运算:
    1. 初始化,左边为部分积,即计算的部分结果,最开始为全$0$,右边为乘数,然后是一个辅助位,最后边全部为丢失位。
    2. 根据辅助位$-MQ$最低位的差值来判断加上什么,若是$1$则加上被乘数的补码,若是$0$则加与被乘数等长的全$0$,若是$-1$则加上被乘数的负数的补码。
    3. 算术右移部分积一位,正数高位补$0$,负数高位补$1$,丢失位多一位。
    4. 继续计算,直到乘数全部被移出。字长为$n+1$位则需要移位计算$n$次。丢失位前的就是全部部分积。
    5. 最后一次不需要移位,再加一次。

$Booth$算法的移位法则,其中$y_n$为$MQ$最低位,$y_{n+1}$为辅助位:

$y_n$(高位) $y_{n+1}$(低位) 操作
0 0 部分积右移一位
0 1 部分积加$[X]_{\text{补}}$,右移一位
1 0 部分积加$[-X]_{\text{补}}$,右移一位
1 1 部分积右移一位

即辅助位减$MQ$最低位的值,若是$1$就加补码,若$0$则加$0$,若$-1$则加负数的补码。

两种乘法的区别:

  原码 补码
计算流程 n轮加法、移位 n轮加法、移位最后进行一次加法
加法的值 +0、+x的原码 +0、+x的补码、+(-x)的补码
判断加值的根据 MQ的最低位 辅助位-MQ的最低位
判断关系 MQ的最低位=1时ACC+x的原码MQ的最低位=0时ACC不变 辅助位-MQ中最低位=1时(ACC)+x的补码辅助位-MQ中最低位=0时ACC不变辅助位-MQ中最低位=-1时ACC+(-x)的补码
移位类型 逻辑右移 算术右移
符号位 不参与运算 参与运算

定点数除法运算

二进制除法运算可以参考十进制的除法运算,将除数乘上一位数,使得乘积最大且不超过被除数,然后将被除数减去这个乘积并左移就得到下一轮运算的被除数。

       1.507
    --------
211 | 318
      211
    --------
      1070
      1055
    --------
        150
        000
    --------
        1500
        1477
    --------
          23
         ...

所以除法就是为了凑和被除数相近的商。

而使用二进制的一位位除法同理:

           0.1101
      ------------
01101 | 01011
        00000
      ------------
         10110
         01101
      ------------
          10010
          01101
      ------------
           01010
           01101
      ------------
            01010
            00000
      ------------
             10100
             01101
      ------------
              0111
  • 进行除法操作时,都是为了找到一位能让商乘除数能最大即余数最小但大于$0$的值。若除数被除数都是小数,可以同时乘一个数变成整数再运算。
  • 所以可以忽略小数点,每确定一位商进行一次减法,若机器字长为$n$位,则得到$n-1$位余数,在余数末尾补$0$,再确定下一位商$0$或$1$,直到确定$n$位商即可停止。
  • 在运算器的组成时出现一个表格,说明在进行除运算时,$ACC$保存被除数和余数,$MQ$保存商,$X$保存除数。

所以同理可以推出恢复余数法,与源码一位法类似,都是计算绝对值最后判断符号。余数加$0$扩大余数就相当于左移一位。

原码恢复余数法:

物理上:

  1. 字长若为$n+1$位,则$ACC$、$MQ$、$X$全部初始化为$n$位,将被除数的绝对值放入$ACC$中,$X$放入除数的绝对值,$MQ$初始化为全$0$。
  2. 将$MQ$的最右边的一位当做当前除运算位,让其进行除运算,运算规则是,默认商$1$$ACC-=X$,即$X$的补码要加上除数的绝对值的负值的补码(减法都由补码的加法实现),判断是否有误。若结果高位为$0$则无误,高位为$1$则有误,错误则商改为$0$,并恢复余数,$ACC$加上$X$中除数的补码。
  3. 将$ACC$和$MQ$的数据连接在一起,全部逻辑左移一位,$MQ$数据低位补$0$$MQ$最高位的$0$移到ACC的最低位。将$ACC$的最高一位抛弃。若是第$i$轮逻辑左移,则$MQ$的后$i$位是当前计算的商的结果。
  4. 从步骤二开始重复,字长若为$n+1$位,则左移$n$次,上商$n+1$次,直到$MQ$中全部是计算结果,则停止计算。此时$MQ$中保存商,$ACC$中保存左移$n$位的余数值,真正的余数应该是结果再乘上$2$的$-n$次方。
  5. 定点小数的小数位隐藏在符号位后面第一位,定点正数的小数位隐藏在最后一位后。
  6. 将两个符号位的异或结果赋值给商最高位。

逻辑上:

  1. 老余数减去除数的绝对值,得到新的余数。
  2. 若新余数为负,即高位为$1$表示是负数,则商$0$,并重新加上除数的绝对值恢复为老余数。
  3. 若新余数为正,则商$1$。
  4. 余数逻辑左移,继续运算。

默认会商$1$,如果发现结果有问题就恢复余数(变成商$0$)。若字长为$n+1$,则只用左移$n$次,上商$n+1$次,最后一次上商余数不左移。

原码加减交替法:

  • 因为恢复余数很麻烦,所以会考虑是否不用恢复余数,直接进行运算得到后面的结果。
  • 假如令原始值为$x$,原始值加上$-y$绝对值的补码结果为$a$$y$绝对值的补码为$b$,按恢复余数法,$a$这个余数是一个负值,所以要加上$b$即$a+b$变成原始值$a+b=x$,这时候商$0$,然后计算下一个商,余数$a+b$左移一位,即$(a+b)\times2=2a+2b$,这时候商$1$看看结果是否正确,即$2a+2b$要减去y绝对值的补码等价于加上$-y$绝对值的补码)$2a+2b-b=2a+b$。
  • 所以如果得到了一个负的余数$a$,可以直接转换到$2a+b$这个结果,即直接左移一位余数再加上除数的补码就可以得到结果。
  • 这就是加减交通法或不恢复余数法。
  • 从而恢复余数法就是当余数为负时商$0$,并+|除数|,再左移,再-|除数|,而加减交替法是当余数为负时商$0$,并左移一位,再+[除数|,若余数为正时商$1$,并左移一位,再-|除数|。
  • 值得注意的是,若在最后一步余数为负,需要商$0$,并加上除数的补码得到正确余数。

逻辑上:

  1. 被除数减去除数的绝对值,得到新的余数。
  2. 余数为负,则商$0$,左移,加上除数绝对值。
  3. 余数为正,则商$1$,左移,减去除数绝对值。
  4. 在最后一步余数为负,需要商$0$,并加上除数的补码得到正确余数。

注意:在定点小数运算时,商只能是小数而不能是整数,所以被除数一定要小于除数,机器判断标准是看第一步计算的商,若第一步计算的商是$1$则代表结果大于$1$,机器就会报错。

补码加减交替法:

  • 符号位参与运算。
  • 被除数÷余数、除数采用双符号位。
  • 被除数和除数同号,则被除数减去除数,异号则被除数加上除数。
  • 余数和除数同号,商$1$,余数左移一位减去除数;
  • 余数和除数异号,商$0$,余数左移一位加上除数。
  • 重复$n$次。
  • 最后一次计算时末位商恒置为$1$,处理简单,而且精度误差也不会超过$2^{-n}$。

逻辑上:

  1. 被除数和除数同号,则被除数减去除数,若异号则被除数加上除数。
  2. 余数和除数异号,则商$0$,左移,加上除数。
  3. 余数和除数同号,则商$1$,左移,减去除数。
  4. 重复$n$次,末位商恒置为$1$。
除法类型 符号位参与运算 加减次数 移位方向 移位次数次数 上商和加减原则 说明
原码加减交替法 N+1或N+2 N 余数的正负 若最终余数为负,需恢复余数
补码加减交替法 N+1 N 余数和除数是否同号 商末位恒置1

其实本质上原码和补码的上商和加减原则是一样的,只是因为除数被去掉符号为正值,所以余数是负就异号,是正就同号。

定点数强制类型转换

  • 无符号数与有符号数:不改变数据内容,只改变解释方式。
  • 长整数转短整数:高位截断,保留低位。
  • 短整数转长整数:符号扩展。
  1. 有符号数和无符号数之间的转换。例如,由$signed$型转换为等长$unsigned$型数据时,符号位成为数据的一部分,即负数转换为无符号数时,数值将发生变化。同理,由$unsigned$转换为$signed$时最高位作为符号位,也可能发生数值变化。
  2. 数据的截取与保留。当一个浮点数转换为整数时,浮点数的小数部分全部舍去,并按整数形式存储。但浮点数的整数部分不能超过整型数允许的最大范围,否则溢出。
  3. 数据转换中的精度丢失。四舍五入会丢失一些精度,截去小数也会丢失一些精度。此外,数据由$long$型转换为$float$型或$double$型时,有可能在存储时不能准确地表示该长整数的有效数字,精度也会受到影响。
  4. 数据转换结果的不确定性。当较长的整数转换为较短的整数时,要将高位截去。例如,$long$型转换为$short$型,只将低$16$位送过去,这样就会产生很大的误差。浮点数降格时,如$double$型转换为$float$型,当数值超过$float$型的表示范围时,所得到的结果将是不确定的。

定点数数据存储与排列

  • 数据最左边的高位就是最高有效字节$MSB$。
  • 数据最右边的低位就是最低有效字节$LSB$。
  • 大端模式:将$MSB$存到最低地址,$LSB$存在最高地址。便于人类阅读。
  • 小端模式:将$MSB$存到最高地址,$LSB$存在最低地址。便于机器读取。
  • 边界对齐:
    • 现代计算机通常是按字节编址即每个字节对应一个地址。也支持按字、按半字、按字节寻址。
    • 假设存储字长为$32$位,则$1$个字=$32bit$,半字$=16bit$。每次访存只能读/写$1$个字。
    • 字地址转换为字节地址,只用逻辑左移两位就可以了,即乘以$4$,因为字长为$32$,而字节长$8$。
    • 使用边界对齐方式会让每个数据都能一次性读完而不用跨行读取,多余的空间用$0$填充。

浮点数

指小数点的位置不固定,如使用科学计数法,如$9.694E2$。

浮点数表示

阶码与尾数

  • 定点数能表示的数字范围有限,但我们不能无限制地增加数据的长度。
  • 类似科学计数法,分为阶符、阶码、数符和尾数四个部分,阶符和阶码反映数值大小、表示范围、小数点实际位置,数符代表浮点数的符号,尾数反映精度。
  • 对于二进制的浮点数,阶码是常用补码或移码表示的定点整数,而尾数是常用原码或补码表示的定点小数。
  • 若阶码的真值为$E$,尾数的真值为$M$,则浮点数的真值为$N=r^E\times M$,其中$r$为阶码的底,即基数,一般为$2$。

尾数规格化

为了提高精度,充分利用尾数有效位数必须进行规格化,规定尾数必须是一个有效值。

  • 左规:出现下溢需要左规,即若尾数的高位是无效值(即为$0$)则会丧失精度,所以我们需要尽可能将尾数多保存一些$1$,从而让最高位为$1$。所以需要让数值左移,让小数点右移,尾数算术左移$n$位,阶码减$n$,直到尾数最高位是有效值。可能会进行多次。
  • 右规:出现上溢需要右规,规范要求小数点要在第一个非$0$的数据右边,如果小数点前有超过$1$个有效位,则需要将数值右移,小数点左移,尾数算术右移$n$位,阶码加$n$,直到小数点在尾数最高位的右边。只需要一次。

规格化浮点数的特点:

  1. 用原码表示的尾数进行规格化,最高位数值一定为$1$
    • 正数为$0.1xx\cdots x$的形式,其最大值表示为$0.11\cdots1$;最小值表示为$0.10\cdots0$。
    • 尾数的表示范围为$\dfrac{1}{2}\leqslant M\leqslant(1-2^{-n})$。
    • 负数为$1.1xx\cdots x$的形式,其最大值表示为1.10\cdots0;最小值表示为$1.11\cdots1$。
    • 尾数的表示范围为$-(1-2^{-n})\leqslant M\leqslant-\dfrac{1}{2}$。
  2. 用补码表示的尾数进行规格化,符号位与最高位数值一定相反:
    • 正数为$0.1xx\cdots x$的形式,其最大值表示为$0.11\cdots1$;最小值表示为$0.10\cdots0$。跟原码一致。
    • 尾数的表示范围为$\dfrac{1}{2}\leqslant M\leqslant(1-2^{-n})$。
    • 负数为$1.0xx\cdots x$的形式,其最大值表示为$1.01\cdots1$;最小值表示为$1.00\cdots0$。(负数的补码$1.0xx\cdots x$取反后就是$1.1xx\cdots x$
    • 尾数的表示范围为$-1\leqslant M\leqslant-(\dfrac{1}{2}+2^{-n})$。(补码中强制规定$1.00\cdots0$就代表$-1$

当浮点数尾数的基数为$2$时,原码规格化数的尾数最高位一定是$1$,补码规格化数的尾数最高位一定与尾数符号位相反。

基数不同,浮点数的规格化形式也不同。当基数为$4$时,原码规格化形式的尾数正数最高两位不全为$0$,负数最高两位不全为$1$;当基数为$8$时,原码规格化形式的尾数正数最高$3$位不全为$0$,负数正数最高$3$位不全为$1$。

如若基数为$8$,则$0.000111$和$1.111010$都不是规格化数,而$1.101010$是规格化。

对于浮点数,上溢和下溢有正负之分:负上溢<负数区<负下溢<$0$<正下溢<正数区<正上溢。

定点浮点区别

假设定点数和浮点数的字长相同。

  • 浮点数表示范围更大。
  • 浮点数精度降低。(由于只取出一部分数据,还有部分长度表示阶码等,所以用于表示尾数的字长减少)
  • 浮点数运算更复杂。(需要规格化,需要做尾数运算和阶码运算)
  • 浮点数只有规格化后才能判断是否溢出。

IEEE 754标准

$IEEE,754$标准就是浮点数标准,为了解决计算机中阶码、尾数使用什么码来表示,各取多少位的问题。

移码定义

  • 移码的定义其实=真值+偏置值,一般取$2^{n-1}$,这时候移码才等于补码符号位取反,若移码采取其他方案则没有这个特点。
  • 在$IEEE,754$标准中,规定移码的偏置值不再是$128$而是$127$,即$2^{n-1}-1$。所以这个标准下的移码与一般的移码不同。
  • 从而真值$-128$的移码为$-1000,0000+0111,1111=1111,1111$$-127$的移码为$0000,0000$$0$的移码为$0111,1111$$127$的移码为$1111,1110$。

IEEE 754定义

  • 分为数符(表示数值正负号)、阶码(用移码表示)、尾数(用原码表示,且默认最高位为$1$,实际尾数位都要加$1$)。
  • 标准中会将全$0$的$-127$(非规格化数)和全$1$的$-128$(无穷大)做特殊的用途,所以短浮点数的真值正常范围是$-126$到$127$。
英文类型 中文类型 数符位 阶码位 尾数位 总位数 十六进制偏置值 十进制偏置值
float 短浮点数 1 8 23 32 7FH 127
double 长浮点数 1 11 52 64 3FFH 1023
long double 临时浮点数 1 15 64 80 3FFFH 16383
  • 令数符为$S$,阶码为$E$,尾数为$M$。
  • 规格化的短浮点数的真值为$(-1)^S\times 1.M\times2^{E-127}$。
  • 规格化的长浮点数的真值为$(-1)^S\times 1.M\times2^{E-1023}$。
  • 短浮点数和长浮点数都隐含一位尾数最高位$1$,即$0.11$为$+1.11$$1.11$为$-1.11$,而临时浮点数没有隐含位。

IEEE 754取值范围

格式 规格化的最小绝对值 规格化的最大绝对值
单精度 $E=1$$M=0$1.0×2^{1-127}=2^{-126} $E=254$$M=.11...1$1.11...1×2^{254-127}=2^{127}×(2-2^{23})
双精度 $E=1$$M=0$1.0×2^{1-1023}=2^{-1022} $E=2046$$M=.11...1$1.11...1×2^{2046-1023}=2^{1023}×(2-2^{-52})
  • 对于规格化短浮点数,只有$1\leqslant E\leqslant 254$时,$(-1)^S\times 1.M\times2^{E-127}$。
  • 当阶码$E$为全$0$,即应该为$-127D$,而尾数$M$不全为$0$时,表示非规格化小数$\pm(0.\textrm{xx...x})_2\times2^{-126}$。(此时最高位就不默认为$1$了,阶码固定设置为$-126$)。
  • 当阶码$E$为全$0$,即应该为$-127D$,而尾数$M$全为$0$时,表示真值$\pm0$,正负看数符。
  • 当阶码$E$为全$1$,即应该为$-128D$,而尾数$M$全为$0$时,表示无穷大$\pm\infty$,正负看数符。
  • 当阶码$E$为全$1$,即应该为$-128D$,而尾数$M$不全为$0$时,表示非数值$NaN$$Not,a,Number$)。如果非法操作如$0\div0$等就会使用到。

尾数运算

由于阶码由原码转换为移码,尾数加减都需要进行原码运算,所以需要两种实现方式。

  • 转换为补码进行加减,再转回原码。
  • 直接用原码加减,符号和数值分开。

浮点数运算

科学计数法加减运算

  1. 对阶:阶数小的向阶数更大的对齐。
    • 因为计算机内部,尾数是定点小数,小数点位置不会变,改变的只是数据的相对位置。
    • 若是阶数大的向阶数小的对齐,则阶数大的尾数值会变大,需要对尾数进行算术左移,若内存不够大很可能会引起最高有效位丢失。
    • 若是阶数小的向阶数大的对齐,则阶数小的尾数值会变小,需要对尾数进行算术右移,若内存不够大很可能会引起最后几位丢失,即精度下降,影响较小。
  2. 尾数加减:阶数不变,对尾数进行相加减。
  3. 规格化,将数据变为整数部分为$0$到$9$的数据:
    • 当尾数加减结果的第一位为$0$时需要左规,直到第一位不为$0$。
    • 当结果的整数部分大于等于$10$需要右规,直到整数部分只有一位。
  4. 舍入:计算机中由于尾数的比特位有限,所以需要舍弃尾数的低位。只有浮点数才会舍入,定点数则没有这个概念。对阶右规格化都会引起舍入。舍入方法有:
    • 直接去除。
    • 非$0$进$1$。
    • 四舍五入。
  5. 判溢出:若运算后阶码超过规定范围则溢出。尾数的溢出未必会导致整体溢出,可以通过第三四步来修补,但是阶码溢出一定会整体溢出。

溢出的情况:

  • 右规和尾数舍入(如果是四舍五入可能导致尾数加一,尾数需要进位,阶码加一,导致阶码上溢)可能引起阶码上溢。
  • 左规可能引起阶码下溢。
  • 对阶不会导致溢出(因为是向大阶对齐,大阶一定不是溢出的)。

浮点数加减运算

浮点数的加减基本上与科学计数法的加减一致。基本上浮点数的运算不可能使用$IEEE,754$的标准,因为位数太长不好计算。所以加减运算一律使用补码。

舍入的方法:

  • “$0$”舍“$1$”入法:类似于十进制数运算中的“四舍五入”法,即在尾数右移时,被移去的最高数值位为$0$,则舍去;被移去的最高数值位为$1$,则在尾数的末位加$1$。这样做可能会使尾数又溢出,此时需再做一次右规。
  • 恒置“$1$”法:尾数右移时,不论丢掉的最高数值位是“$1$”还是“$0$”,都使右移后的尾数末位恒置“$1$”。这种方法同样有使尾数变大和变小的两种可能。

假如加减的结果为$11100,10.110001011$,因为尾数符号位为$10$代表溢出了,所以需要规格化。

使用$0$舍$1$入法,将尾数整体右移,并将符号位的低位移到尾数高位,阶码加移位数,符号位修改,从而变成了$11101,11.011000101$,溢出$1$,最高位为$1$,使用$0$舍$1$入时需要加$1$,从而变成$11101,11.011000110$。(假如尾数为全$1$,则加$1$后又会高位溢出,还需要一次右规)。恒置$1$法的答案是一样的。

浮点数强制类型转换

类型 16位机器 32位机器 64位机器
char 8 8 8
short 16 16 16
int 16 32 32
long 32 32 64
long long 64 64 64
float 16 32 32
double 64 64 64

无损转换:

  • $char$→$int$→$long$→$double$。
  • $float$→$double$。

由于定点数和浮点数不同,浮点数使用阶码+尾数的存储方式存储,所以定点数数值精度看位长就可以了,而浮点数数值精度看尾数长度,按$IEEE,754$标准有一个隐含的高位$1$,所以$double$尾数长度为$53$位。对于$32$位机器$long$是$32$位,所以转换到$double$的$53$位没有损失,而对于$64$位机器$long$是$64$位,$double$还是$53$位,这时候转换就会产生损失了。

$int$与$float$转换

  • $int$:表示整数,范围$[-2^{31},2^{31}-1]$,有效数字$32$位。
  • $float$:表示整数及小数,范围$\pm[2^{-126},2^{127}×(2-2^{-23})]$,有效数字$23+1=24$位。
  • $int$→$float$:可能损失精度。
  • $float$→>$int$:可能溢出及损失精度。

算术逻辑单元

即运算器中的$ALU$。

原理

ALU结构

  • 输入信号有一个操作数的输入口,输出信号有一个运算结果输出口,旁边还有一个控制单元$CU$发出的控制信号接口,会输入指令译码。
  • 机器字长就是指$ALU$可以同时处理多长的数据。为了保存结果,寄存器的字长与机器字长相等。
  • 核心为带标志加法器。
  • 整体$ALU$$A$、$B$两个操作数输入;$Cin$、$Cout$进位输入和进位输出;$ALUop$操作控制端(决定执行哪种操作);$ZF$、$OF$、$SF$、$CF$四个标志位;$F$输出。
  • 整体$ALU$的每一位$ALU$$A$、$B$两个操作数输入;$Cin$、$Cout$进位输入和进位输出;由多路选择开关(多路选择器)$MUX$实现的$ALUop$操作控制端;一位全加器;$F$输出。

逻辑运算

  • 与可以用*表示,如$A*B$。
  • 或可以用+表示,如$A+B$。
  • 优先级上类比乘法加法,与优先于或。
  • 具有类似的分配律结合律。
  • 与非:先与后非。
  • 或非:先或后非。
  • 异或:相异为$1$,相同为$0$。
  • 同或:相同为$1$,相异为$0$。

加法器实现

加减法逻辑电路

  • 加法器实际上能实现加法和减法两种运算。
  • 加法即是$X$的补码加上$Y$的补码,而减法即使$X$的补码减去$Y$的补码。
  • 而减去的操作能通过加法来实现,不管是补码减法,还是无符号数减法,都是用被减数$X$加上减数$Y$的负数的补码来实现的。所以加减法被统一为加法。
  • 根据公式,减数$Y$的负数的补码为$\overline{Y}+1$(即全部取反加一),因此,在加法器的$Y$输入端用一个反向器实现,并用控制端$Sub$控制多路选择器$MUX$判断是否将$Y$的各位取反后,输入$Y$端进行加操作。
  • 所以在输入$X$和$Y$时,同时将$Sub$作为低位进位送到加法器。当$Sub$为$1$时,做减法,当$Sub$为$0$时,做加法。

一位全加器

  • 一位全加器$FA$中,令被加数为$A$,被加数从低到高的位数为$A_i$,令加数为$B$,被加数从低到高的位数为$B_i$,令来自低位$i-1$的进位为$C_{i-1}$,本位的和为$S_i$。$S_i=A_i+B_i+C_{i-1}$。
  • 输入$A_i$、$B_i$、$C_{i-1}$,输出$S_i$、$C_i$。
  • 输入中有奇数个$1$时为$1$(异或):$S_i=A_i\oplus B_i\oplus C_{i-1}$。
  • 输入中至少两个$1$才会高位进$1$,一种情况是两个本位都是$1$,另一种情况是只有一个是$1$且来自低位的进位是$1$$C_i=A_iB_i+(A_i\oplus B_i)C_{i-1}$。

串行加法器

  • 基于一个一位全加器,一位一位串行进入加法器运算。对比一位全加器,需要保存一个进位触发器用来保存进位位,进位触发器初始化值为$0$。
  • 如果操作数长$n$位加法就要分$n$次进行,每次产生一位和,并且串行逐位地送回寄存器。

串行进位并行加法器

  • 把$n$个全加器串接起来,就可进行两个$n$位数的相加。前一个全加器的进位输出将作为下一个全加器的输入。
  • 串行进位又称为行波进位,每一级进位直接依赖于前一级的进位,即进位信号是逐级形成的。所以不可能比单纯的串行全加器快很多。
  • 加快进产生和提高传递速度是关键。

并行进位并行加法器

  • 由于$S_i=A_i\oplus B_i\oplus C_{i-1}$,所以计算的重点是计算$C_i$,而$C_i=A_iB_i+(A_i\oplus B_i)C_{i-1}$,通过递归可以不断展开:$C_i=A_iB_i+(A_i\oplus B_i)(A_{i-1}B_{i-1}+(A_{i-1}\oplus B_{i-1})C_{i-2})$一直可以递归到$C_0$,而$A_i$、$B_i$、$C_0$都是一开始可以知道的,所以第$i$位向更高位的进位$C_i$可根据被加数、加数的第$1$到$i$位,再结合$C_0$即可确定。
  • 将$G_i=A_iB_i$$P_i=A_i\oplus B_i$,所以式子得到化简:$C_i=A_iB_i+(A_i\oplus B_i)C_{i-1}=G_i+P_iC_{i-1}$。
  • 所以$C_1=G_1+P_1C_0$$C_2=G_2+P_2C_1=G_2+P_2G_1+P_2P_1C_0$$C_3=G_3+P_3C_2=G_3+P_3G_2+P_3P_2G_1+P_3P_2P_1C_0$……所以一直到最后面每个$C_i$都可以用对应的$G_i$和$P_i$计算,这时候$C_i$可以不用递归来计算,可以用一开始就知道的$P_i$、$G_i$和$C_0$计算得到,从而这时候每一位的计算都可以一开始就同时进行了而不用依赖前面的计算。
  • 各级进位信号同时形成,又称为先行进位、同时进位。
  • $G_i$称为进位产生函数,因为$G_i$是通过$A_i$和$B_i$相与,只有同时为$1$才会产生$1$。
  • $P_i$称为进位传递函数,$P_i$是通过$A_i$和$B_i$异或,实际上$P_i$为$1$时,只有此时$C_{i-1}$才能为$1$,否则为$0$。

单级先行进位加法器

  • 称为组内并行、组间串行进位方式。
  • 由于逻辑表达式越长就代表电路实现越复杂,所以一般会最多用$4$个$FA$和一些新的线路、运算逻辑组成一个运算单元进行串联进位计算。
  • 组内的信息可以并行同时得到,但是组件信息需要串行进位。这时虽然实现简单,但是效率对比并行进位并行加法器还是下降了。

多级先行进位加法器

  • 多级先行进位方式,又称为组内并行、组间并行进位方式。
  • 为了解决这个问题按照并行进位并行加法器的思路继续对每一组的数据进行计算。
  • 令$G_1^=G_4+P_4G_3+P_4P_3G_2+P_4P_3P_2G_1$为组进位产生函数,$P_1^=P_4P_3P_2P_1$为组进位传递函数。一开始输入就能确定,所以这些都是一开始就能确定的。
  • 所以$C_4=G_1^*+P_1^C_0$$C_8=G_2^+P_2^C_4=G_2^+P_2^G_1^+P_2^*P_1^*C_0$C_{12}=G_3^*+P_3^*C_8=G_3^*+P_3^*G_2^*+P_3^*P_2^*G_1^*+P_3^*P_2^*P_1^*C_0\cdots
  • 所以$4$位$BCLA$(成组先行进位电路)只要输出$G_i$和$P_i$就可以在计算机中计算得到$C_{4i}$了。

带标志加法器

上面都是无符号数加法器,要实现有符号数运算还需要添加相应逻辑电路。

零标志位

即$ZF$$zero,flag$。判断当前数字是否为全0值。

  • $ZF=1$表示结果为$0$。
  • 无论是有符号数还是无符号数,$ZF$都有意义。
  • 通过加法电路和最后的取反操作实现。

符号标志位

即$SF$symbol,flag$)。判断当前结果符号。

  • $SF=1$表示结果为负值。
  • 当产生溢出时,符号标志位置出错。

进/借位标志位

即$CF$$carry,flag$)。表示无符号整数数加/减运算时的进位/借位(溢出)。

  • $CF=1$表示无符号数加法溢出/减法借位。
  • 对于有符号数的整数运算,$CF$没有意义。

溢出标志位

即$OF$$overflow,flag$)。表示带符号整数运算时结果发生溢出。

  • $OF=1$表示溢出。
  • 对于无符号整数运算,$OF$没有意义。

对于有符号数的溢出判断方式有:

  1. 采用一位符号位:思想为:正正得负或负负得正则为溢出,其他情况无溢出。
    • 设$A$符号为$A_S$、$B$符号为$B_S$、运算结果符号为$S_S$。
    • 溢出逻辑表达式为$V=A_SB_S\overline{S_S}+\overline{A_SB_S}S_S$。
  2. 采用双符号位:$s1$、$s2$表示运算结果的两个符号位:
    • $s1s2=00$:表示正数,无溢出。
    • $s1s2=01$:表示结果正溢出 ,即正正得负,且$s2$表示当前运算符号为负,$s1$表示原本正确的符号应该为正。
    • $s1s2=10$:表示结果负溢出 ,即负负得正,且$s2$表示当前运算符号为正,$s1$表示原本正确的符号应该为负。
    • $s1s2=11$:表示结果为负数,无溢出
  3. 采用一位符号位,根据数据位和符号位的进位情况判断溢出:
    • $C0$:表示运算时符号位是否产生进位,若符号位产生进位则为$1$,否则为$0$。
    • $C1$:表示运算时最高数值位是否产生进位,若最高数值位产生进位则为$1$,否则为$0$。
    • $V=C0\oplus C1$:若$V=0$表示无溢出;$V=1$表示有溢出。