文章目录
无符号数和有符号数
无符号数
无符号数,即没有符号的数(只有数值部分),在寄存器中的每一位均可用来存放数值,即寄存器的位数就反映了无符号数的表示范围。
而存放有符号数时,则需留出位置存放符号。因此,在机器字长相同时,无符号数与有符号数所对应的数值范围是不同的。以机器字长 16 位为例,无符号数的表示范围为 0 ~ 65535,而有符号数的表示范围为 -32768 ~ 32767(此数据对应补码表示)
有符号数
把符号“数字化”的数称为机器数,而把带“+”或“-”符号的数称为真值。一旦符号数字化后,符号和数值就形成了一种新的编码,这些编码就是原码、补码、反码和移码。
原码表示法
(1)定义
原码是机器数中最简单的一种表示形式,符号位为 0 表示正数,符号位为 1 表示负数,数值位即真值的绝对值,故原码表示又称为带符号的绝对值表示。
整数原码的定义为:
[
x
]
原
=
{
0
,
x
2
n
>
x
≥
0
2
n
−
x
0
≥
x
>
−
2
n
[x]_{原}=\left\{ \begin{array}{ll} 0,x & 2^n > x \geq 0 \\ 2^n -x & 0 \geq x > -2^n \end{array} \right.
[x]原={0,x2n−x2n>x≥00≥x>−2n式中,
x
x
x 为真值,
n
n
n 为整数的位数。例如,当
x
x
x = +1110 时,
[
x
]
原
[x]_{原}
[x]原 = 0,1110;当
x
x
x = -1110 时,
[
x
]
原
[x]_{原}
[x]原 = 1,1110 =
2
4
2^4
24 - (-1110)
小数原码定义为:
[
x
]
原
=
{
x
1
>
x
≥
0
1
−
x
0
≥
x
≥
−
1
[x]_{原}=\left\{ \begin{array}{ll} x & 1 > x \geq 0 \\ 1 -x & 0 \geq x \geq -1 \end{array} \right.
[x]原={x1−x1>x≥00≥x≥−1 式中,
x
x
x 为真值。例如,当
x
x
x = 0.1101时,
[
x
]
原
[x]_{原}
[x]原 = 0.1101;当
x
x
x = -0.1101 时,
[
x
]
原
[x]_{原}
[x]原 = 1.1101 = 1 - (-0.1101)
可见 [ + 0 ] 原 [+0]_{原} [+0]原 不等于 [ − 0 ] 原 [-0]_{原} [−0]原,即原码中的“零”有两种表示形式。
原码表示简单明了,并易于和真值进行转换。但是用原码进行加法运算时,如果两个操作数符号不同,先要判断两个数绝对值大小,然后将绝对值大的数减去绝对值小的数,结果的符号以绝对值大的数为准。运算步骤既复杂又费时,而且本来是加法运算却要用到减法器实现。
那么能否在计算机中只设加法器,只做加法操作呢?如果能找到一个与负数等价的正数来代替该负数,就可把减法操作用加法代替。而机器使用补码时,就能满足此要求。
补码表示法
(1)补数的概念
在日常生活中,常会遇到“补数”的概念。例如,时钟指示 6 点,欲使它指示 3 点,既可将分针顺时针转 9 圈,又可将分针逆时针转 3 圈。由于时钟的时针转一圈能指示 12 个小时,这样,-3 和 +9 对时钟而言其作用是一样的。在数学中,称 12 为模,写作 mod 12,而称 +9 是 -3 以 12 为模的补数,记作 -3 ≡ \equiv ≡ +9 (mod 12)。
可以得到以下结论:
- 只要确定了 “模”,就可找到一个与负数等价的正数来代替此负数,该正数即为负数的补数,这个正补数可以用模加上负数本身求得。
- 正数的补数就是该正数本身。
- 一个正数和一个负数互为补数时,它们绝对值之和即为模数。
将补数的概念用到计算机中,便出现了补码这种机器数.
(2)补码的定义
整数补码的定义为:
[
x
]
补
=
{
0
,
x
2
n
>
x
≥
0
2
n
+
1
+
x
0
>
x
≥
−
2
n
(
m
o
d
2
n
+
1
)
[x]_{补}=\left\{ \begin{array}{ll} 0,x & 2^n > x \geq 0 \\ 2^{n+1} + x & 0 > x \geq -2^n\ (mod\ 2^{n+1}) \end{array} \right.
[x]补={0,x2n+1+x2n>x≥00>x≥−2n (mod 2n+1) 式中,
x
x
x 为真值,
n
n
n 为整数的位数。即正数的原码和补码相同。当
x
x
x = -1101 时,
[
x
]
补
[x]_{补}
[x]补 = 1,0011 =
2
n
+
1
2^{n+1}
2n+1 + (-1101) = 100000 - 1101。
小数补码的定义:
[
x
]
补
=
{
x
1
>
x
≥
0
2
+
x
0
>
x
≥
−
1
(
m
o
d
2
)
[x]_{补}=\left\{ \begin{array}{ll} x & 1 > x \geq 0 \\ 2 + x & 0 > x \geq -1\ (mod\ 2) \end{array} \right.
[x]补={x2+x1>x≥00>x≥−1 (mod 2) 式中,
x
x
x 为真值。例如,当
x
x
x = -0.0110 时,
[
x
]
补
[x]_{补}
[x]补 = 1.1010 = 2 + x = 10.0000 - 0.0110
显然,补码中的“零”只有一种表示形式。引入补码的概念是为了消除采用原码所需的减法运算,但是根据补码的定义,在形成补码的过程中又出现了减法(求负数的补码时)。所以一般采用下面的方式来求补码
(3)求补码的快捷方式
正数的补码和原码相同。
当真值为负时,补码可用原码除符号位外每位取反,末位加 1 求得。
反码表示法
反码通常同来作为由原码求补码或者由补码求原码的中间过渡。反码的定义如下:
整数反码定义为:
[
x
]
反
=
{
0
,
x
2
n
>
x
≥
0
(
2
n
+
1
−
1
)
+
x
0
≥
x
>
−
2
n
(
m
o
d
(
2
n
+
1
−
1
)
)
[x]_{反}=\left\{ \begin{array}{ll} 0,x & 2^n > x \geq 0 \\ (2^{n+1}-1) + x & 0 \geq x > -2^n\ (mod(2^{n+1}-1)) \end{array} \right.
[x]反={0,x(2n+1−1)+x2n>x≥00≥x>−2n (mod(2n+1−1)) 式中,
x
x
x 为真值,
n
n
n 为整数的位数。例如,
x
x
x = +1101 时,
[
x
]
反
[x]_{反}
[x]反 = 0,1101;
x
x
x = -1101 时,
[
x
]
反
[x]_{反}
[x]反 = 1,0010
小数反码定义为:
[
x
]
反
=
{
x
1
>
x
≥
0
(
2
−
2
−
n
)
+
x
0
≥
x
>
−
2
n
(
m
o
d
(
2
−
2
−
n
)
)
[x]_{反}=\left\{ \begin{array}{ll} x & 1 > x \geq 0 \\ (2-2^{-n}) + x & 0 \geq x > -2^n\ (mod(2-2^{-n})) \end{array} \right.
[x]反={x(2−2−n)+x1>x≥00≥x>−2n (mod(2−2−n)) 式中,
x
x
x 为真值,
n
n
n 为小数的位数。例如,
x
x
x = + 0.0110,
[
x
]
反
[x]_{反}
[x]反 = 0.0110;
x
x
x = -0.0110,
[
x
]
反
[x]_{反}
[x]反 = (
2
−
2
−
4
2-2^{-4}
2−2−4) +
x
x
x = 1.1111 - 0.0110 = 1.1001
可见,反码中的“零”也有两种表示形式。
综上所述,三种机器数的特点可归纳如下:
- 三种机器数的最高位均为符号位。符号位和数值部分之间可用 ‘.’(对于小数) 或 ‘,’(对于整数)隔开。
- 当真值为正时,原码、补码和反码的表示形式均相同,即符号位用 “0” 表示,数值部分与真值相同。
- 当真值为负时,原码、补码和反码的表示形式不同,但其符号位都用“1”表示,而数值部分有这样的关系,即补码是原码除符号位外每位取反末位加 1,反码是原码除符号位外每位取反。
移码表示法
当真值用补码表示时,由于符号位和数值部分一起编码,与习惯上的表示法不同,因此人们很难从补码的形式上直接判断其真值的大小。例如,十进制数 21 的补码为 0,10101,-21 的补码为 1,01011,上述补码中的 “,” 在计算机内部是不存在的,因此,从代码形式看,符号位也是一位二进制数,按这 6 位二进制代码比较大小的话,会得出 101011 > 010101,其实恰恰相反!
如果对每个真值 加上
2
n
2^n
2n(
n
n
n 为整数的位数),情况就发生了变化。还是上面的例子,
x
x
x = 10101 加上
2
5
2^5
25 可得 10101 + 100000 = 110101,
x
x
x = -10101 + 100000 = 001011,比较它们的结果可见 110101 > 001011,这样一来,从 6 位代码本身就可以看出真值的实际大小。由此可得移码的定义为:
[
x
]
移
=
2
n
+
x
(
2
n
>
x
≥
−
2
n
)
[x]_{移} = 2^n+x\ (2^n > x \geq -2^n)
[x]移=2n+x (2n>x≥−2n) 式中,
x
x
x 为真值,
n
n
n 为整数的位数。
用移码判断大小符合人们的习惯,所以浮点数的阶码常用移码表示。
通过观察发现,同一个真值的移码和补码仅差一个符号位。所以移码和补码仅仅是符号位不同,且移码便于直接比较大小(注意正数的移码也不再等于原码、反码和补码)。而且移码中的“零”只有一种表示形式。
数的定点表示和浮点表示
在计算机中,小数点不用专门的器件表示,而是按约定的方式标出,共有两种方法表示小数点的存在,即定点表示和浮点表示。
定点表示
小数点固定在某一位置的数为定点数,在计算机中,通常将数据的小数点固定在数据的最高位之前或者最低位之后。前者称为定点小数(纯小数),后者称为定点整数:
- 定点小数是纯小数,约定的小数点位置在符号位之后、有效数值部分最高位之前。若数据 x x x 的形式为 x = x 0 . x 1 x 2 … x n x = x_0.x_1x_2…x_n x=x0.x1x2…xn(其中 x 0 x_0 x0 为符号位, x 1 x_1 x1 ~ x n x_n xn 是数值的有效部分,也称为尾数, x 1 x_1 x1为最高有效位)
- 定点整数是纯整数,约定的小数点位置在有效数值部分最低位之后。若数据 x x x 的形式为 x = x 0 x 1 x 2 … x n x = x_0x_1x_2…x_n x=x0x1x2…xn(其中 x 0 x_0 x0 为符号位, x 1 x_1 x1 ~ x n x_n xn 是数值部分, x n x_n xn 为最低有效位)
采用定点数的机器称为定点机,在定点机中,由于小数点的位置固定不变,对于既有整数又有小数的原始数据(即不是纯小数或纯整数时),需要设定一个比例因子,数据按其缩小成纯小数或扩大成纯整数再参加运算,运算结果,根据比例因子,还原成实际数值。若比例因子选择不当,往往会使运算结果产生溢出或降低数据的有效精度。
定点数表示法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大或特别小的数,但均可用浮点数表示!
浮点表示
浮点数即小数点的位置可以浮动的数,这种表达方式利用科学计数法来表达实数,例如 352.47 = 3.5247 *
1
0
2
10^2
102 = 3524.7 *
1
0
−
1
10^{-1}
10−1 = 0.35247 ×
1
0
3
10^{3}
103。通常,浮点数被表示成:
N
=
S
×
r
j
N=S × r^j
N=S×rj 式中,
S
S
S 为尾数(可正可负),
j
j
j 为阶码(可正可负),
r
r
r 是基数(基值)。在计算机中,基数可取 2,4,8,16 等。
以基数为 2 为例,数 N N N 可写成下列不同的形式: N = 11.0101 = 0.110101 × 2 10 = 1.10101 × 2 1 = 1101.01 × 2 − 10 = 0.00110101 × 2 100 N = 11.0101=0.110101 × 2^{10}=1.10101 × 2^{1}=1101.01 × 2^{-10}=0.00110101 × 2^{100} N=11.0101=0.110101×210=1.10101×21=1101.01×2−10=0.00110101×2100。
为了提高数据精度以及便于浮点数的比较,在计算机中规定浮点数的尾数用纯小数表示,故上例中的 0.110101 × 2 10 0.110101 × 2^{10} 0.110101×210 和 0.00110101 × 2 100 0.00110101 × 2^{100} 0.00110101×2100 是可以采用的。此外,将尾数最高位为 1 的浮点数称为规格化数,即 0.110101 × 2 10 0.110101 × 2^{10} 0.110101×210 为浮点数的规格化形式。浮点数表示成规格化形式后,其精度最高。
(1)浮点数的表示形式
浮点数由阶码 j j j 和尾数 S S S 及其符号位组成。阶码是整数,阶符和阶码的位数 m m m 合起来反映浮点数的表示范围及小数点的实际位置;尾数是小数,其位数 n n n 反映了浮点数的精度;数符 S f S_f Sf 代表浮点数的正负。
(2)浮点数的表示范围
以通式 N = S × r j N=S × r^j N=S×rj 为例,设浮点数阶码的数值位取 m m m 位,尾数的数值位取 n n n 位,当浮点数可为非规格化数时,它在数轴上的表示范围如上图所示。
由图可见,其最大正数为 2 ( 2 m − 1 ) × ( 1 − 2 − n ) 2^{(2^m-1)} × (1-2^{-n}) 2(2m−1)×(1−2−n);最小正数为 2 − ( 2 m − 1 ) × 2 − n 2^{-(2^m-1)} × 2^{-n} 2−(2m−1)×2−n;最大负数为 − 2 − ( 2 m − 1 ) × 2 − n -2^{-(2^m-1)} × 2^{-n} −2−(2m−1)×2−n;最小负数为 − 2 ( 2 m − 1 ) × ( 1 − 2 − n ) -2^{(2^m-1)} × (1-2^{-n}) −2(2m−1)×(1−2−n)。当浮点数阶码大于最大阶码时,称为上溢,此时机器停止运算,进行中断溢出处理;当浮点数阶码小于最小阶码时,称为下溢,此时溢出的数绝对值很小,通常将尾数各位强置为 0,按机器零处理,此时机器可以继续运行。
一旦浮点数的位数确定后,合理分配阶码和尾数的位置,直接影响浮点数的表示范围和精度。
(3)浮点数的规格化
若不对浮点数的表示作出明确规定,同一个浮点数的表示就不是唯一的。而且为了提高浮点数的精度,其尾数必须为规格化数。如果不是规格化数,就要通过修改阶码并同时左右移尾数的方法,使其变成规格化数,此过程称为规格化。
对于基数不同的浮点数,因其规格化数的形式不同,规格化过程也不同。
- 基数为 2 时,尾数最高位为 1 的数为规格化数。规格化时,尾数左移一位,阶码减 1(左规);尾数右移一位,阶码加 1(右规)。
- 基数为 4 时,尾数最高两位不全为零的数为规格化数。规格化时,尾数左移两位,阶码减 1;尾数右移两位,阶码加 1。
- 基数为 8 时,尾数最高三位不全为零的数为规格化时。规格化时,尾数左移三位,阶码减 1;尾数右移三位,阶码加 1。
浮点机中一旦基数确定后就不再变了,而且基数是隐含的,故不同基数的浮点数表示形式完全相同。但基数不同,对数的表示范围和精度都有影响。
定点数和浮点数的比较
① 当浮点机和定点机中数的位数相同时,浮点数的表示范围比定点数的大得多。
② 当浮点数为规格化数时,其相对精度比定点数高。
③ 浮点数运算要分阶码和尾数部分,而且运算结果都要求规格化,故浮点运算步骤比定点运算步骤多,运算速度比定点运算的低,运算线路比定点运算的复杂。
④ 在溢出的判断方法上,浮点数是对规格化数的阶码进行判断,而定点数是对数值本身进行判断。
IEEE 754 标准
现代计算机中,浮点数一般采用 IEEE 指定的国际标准,这种表示形式如下:
(1) S S S 为数符,它表示浮点数的正负,但与其有效位(尾数)是分开的。
(2)阶码 E E E 用移码表示,基数固定为 2。阶码的真值都被加上一个常数(偏移量,参考移码的定义)。
(3)尾数 M M M 用原码,且隐藏尾数最高位 1。为了提高精度,尾数部分通常都是规格化表示,尾数的最高位始终是1,因此我们完全可以省略掉该位。
常用的浮点数包括 32 位和 64 位:
符号位 S S S | 阶码 E E E | 尾数 M M M | 总位数 | |
---|---|---|---|---|
32 位 | 1 | 8 | 23 | 32 |
64 位 | 1 | 11 | 52 | 64 |
所以,一个规格化 32 位浮点数
x
x
x 的真值为:
x
=
(
−
1
)
S
∗
2
E
−
127
∗
(
1.
M
)
x = (-1)^S * 2^{E-127} * (1.M)
x=(−1)S∗2E−127∗(1.M) 一个规格化 64 位浮点数
x
x
x 的真值为:
x
=
(
−
1
)
S
∗
2
E
−
1023
∗
(
1.
M
)
x = (-1)^S * 2^{E-1023} * (1.M)
x=(−1)S∗2E−1023∗(1.M)
定点运算
移位运算
(1)移位运算的数学意义
计算机中小数点的位置是事先约定的,因此,二进制表示的机器数在相对于小数点作 n n n 位左移或右移时,其实质就是该数乘以或除以 2 n 2^n 2n。
移位运算称为移位操作,对计算机来说,有很大的实用价值。例如,当某计算机没有乘除法运算线路时,可以采用移位和加法结相结合的方式,实现乘(除)运算。
(2)算数移位规则
计算机中机器数的长度往往是固定的,当机器数左移 n n n 位或右移 n n n 位时,必然会使其 n n n 位低位或 n n n 位高位出现空位。那么,对空出的空位应该添补 0 还是 1 呢?这与机器数采用有符号数还是无符号数有关。
无符号数的移位称为逻辑移位,逻辑左移和逻辑右移后出现的空位均以 0 添补。
有符号数的移位称为算术移位:对于正数,由于 [ x ] 原 = [ x ] 反 = [ x ] 补 = 真 值 [x]_{原}=[x]_{反}=[x]_{补}=真值 [x]原=[x]反=[x]补=真值,故移位后出现的空位均以 0 添补;对于负数,由于原码、补码和反码的表示形式不同,所以移位时的添补规则也不同。必须注意的是:算术移位中不论是正数还是负数,移位后的符号位均不变,移的是数值部分,补的也是数值部分,这是算术移位的重要特点。
真值 | 码制 | 添补代码 |
正数 | 原码、补码、反码 | 0 |
负数 | 原码 | 0 |
补码 | 左移添 0 | |
右移添 1 | ||
反码 | 1 |
由上表可以得到如下结论:
① 机器数为正时,无论是左移还是右移,添补代码均为 0;
② 由于负数的原码数值部分与真值相等,故在移位时只要使符号位不变,其空位均添 0 即可;
③ 由于负数的反码各位除符号位外与负数的原码正好相反,故移位后所添的代码应与原码相反,即全部添 1;
④ 负数的补码左移时,因空位出现在低位,则添补的代码与原码相同,即添 0;右移时因空位出现在高位,则添补的代码应与反码相同,即添 1(也可以理解为补码算数右移时,添补的与符号位相同)。
加法和减法运算
现代计算机中都采用补码作加减法运算。
原因如下:
若计算机采用原码计算,在进行加法时,如果两个数符号不同,先要判断两个数绝对值大小,然后将绝对值大的数减去绝对值小的数,结果的符号以绝对值大的数为准,这样运算步骤既复杂又费时,而且本来是加法运算却要用到减法器实现;在进行减法时,虽然可以把减法转换为加法来做,但还是避免不了两个符号不同的数相加的情况,避免不了用到减法器。如果能找到一个与负数等价的正数来代替该负数,就可把需减法器做的减法操作用加法代替。而机器使用补码时就能满足此要求,因为补码的思想就是将负数用一个等价的正数来代替。
(1)补码加减法运算的公式
补码加法的基本公式如下:
整数:
[
A
]
补
+
[
B
]
补
=
[
A
+
B
]
补
(
m
o
d
2
n
+
1
)
[A]_{补} + [B]_{补}=[A+B]_{补} \ (mod\ 2^{n+1})
[A]补+[B]补=[A+B]补 (mod 2n+1)
小数:
[
A
]
补
+
[
B
]
补
=
[
A
+
B
]
补
(
m
o
d
2
)
[A]_{补} + [B]_{补}=[A+B]_{补} \ (mod\ 2)
[A]补+[B]补=[A+B]补 (mod 2)
由于 A − B = A + ( − B ) A-B=A+(-B) A−B=A+(−B),所以补码减法的基本公式如下:
整数:
[
A
−
B
]
补
=
[
A
+
(
−
B
)
]
补
=
[
A
]
补
+
[
−
B
]
补
(
m
o
d
2
n
+
1
)
[A-B]_{补}=[A+(-B)]_{补}=[A]_{补} + [-B]_{补}\ (mod\ 2^{n+1})
[A−B]补=[A+(−B)]补=[A]补+[−B]补 (mod 2n+1)
小数:
[
A
−
B
]
补
=
[
A
+
(
−
B
)
]
补
=
[
A
]
补
+
[
−
B
]
补
(
m
o
d
2
)
[A-B]_{补}=[A+(-B)]_{补}=[A]_{补} + [-B]_{补}\ (mod\ 2)
[A−B]补=[A+(−B)]补=[A]补+[−B]补 (mod 2)
用补码表示的两个数在进行加减法运算时,连同符号位一起相加,符号位产生的进位自然丢掉。
[ − B ] 补 [-B]_{补} [−B]补 由 [ B ] 补 [B]_{补} [B]补 连同符号位在内,每位取反,末位加 1 而得。
例1:设 A = 0.1011 , B = − 0.0101 A=0.1011,B=-0.0101 A=0.1011,B=−0.0101,求 [ A + B ] 补 [A+B]_{补} [A+B]补。
按模 2 的意义,最左边的 1 丢掉,故 [ A + B ] 补 = 0.0110 [A+B]_{补}=0.0110 [A+B]补=0.0110
例2:设 A = − 1001 , B = − 0101 A=-1001,B=-0101 A=−1001,B=−0101,求 [ A + B ] 补 [A+B]_{补} [A+B]补。
按模 2 4 + 1 2^{4+1} 24+1 的意义,最左边的 1 丢掉。
例3:设机器字长为 8 位(含 1 位符号位),若
A
=
+
15
,
B
=
+
24
A=+15,B=+24
A=+15,B=+24,求
[
A
−
B
]
补
[A-B]_{补}
[A−B]补并还原成真值。
由补码求原码时,根据“补码的补码就是原码”。
可见,不论操作数是正还是负,在做补码加减法时,只需将符号位和数值部分一起参加运算,并且将符号位产生的进位自然丢掉即可。
(2)溢出判断
例4:设机器字长为 8 位(含 1 位符号位),若
A
=
−
93
,
B
=
+
45
A=-93,B=+45
A=−93,B=+45,求
[
A
−
B
]
补
[A-B]_{补}
[A−B]补。
[
A
−
B
]
补
=
0
,
01110110
[A-B]_{补}=0,01110110
[A−B]补=0,01110110(结果补码的符号位与A和(-B)补码的符号位不同),还原成真值得
A
−
B
=
118
A-B=118
A−B=118,结果出错。这是因为
A
−
B
=
−
138
A-B=-138
A−B=−138 超出了机器字长所能表示的范围。在计算机中,这种超出机器字长的现象叫溢出。
补码顶点加减运算判断溢出有两种方法:
-
一位符号位判断溢出。
实际进行加法操作的两个数(减法时即为被减数和“求补”后的减数)符号相同,其结果的符号与原操作数的符号不同,即为溢出。① 对于加法,只有在正数加正数、负数加负数的情况下可能出现溢出,符号不同的两个数是不会溢出的。
② 对于减法,只有在正数减负数(相当于正数加正数),负数减正数(相当于负数加负数)这两种情况下才可能出现溢出,符号相同的两个数相减(等同于符号不同的两个数相加)是不会溢出的。 -
两位符号位判断溢出。
使用双符号位,两个符号位均与单符号位时的相同。做加法时,2 位符号位要连同数值部分一起参加运算,而且高位符号位产生的进位自动丢失,便可得正确结果。当结果的两个符号位不同时,表示溢出,否则无溢出。不论是否发生溢出,高位(第一位)符号位永远代表真正的符号。
这里需要说明一点,采用双符号位方案时,寄存器或主存中的操作数只需保存一位符号位即可,因为任何正确的数,两个符号位的值是相同的;而双符号位在加法器中又是必要的,故在相加时,寄存器中一位符号的值要同时送到加法器的两位符号位的输入端。
乘法运算
(1)笔算乘法的改进
若计算机完全模范笔算乘法步骤,将会有两大困难:其一,将多个位积一次相加,机器难以实现;其二,乘积位数增长了一倍,这将造成器材的浪费和运算时间的增加。因此,对笔算乘法进行改进。
如上图所示,两数相乘的过程,可视为加法和移位(乘
2
−
1
2^{-1}
2−1相当于做一位右移)两种运算,这对计算机来说是非常容易实现的。
上述过程过程可归纳如下:
① 乘法运算可用移位和加法来实现,两个四位数相乘,总共需要进行 4 次加法运算和 4 次移位。
② 由乘数的末位值确定被乘数是否与原部分积相加,然后右移一位,形成新的部分积;同时乘数也要右移一位,由次低位作新的末位,空出最高位放部分积的最低位(如上图乘数中黑色部分所示)。
③ 每次做加法时,被乘数仅仅与原部分积的高位相加,其低位被移至乘数所空出的高位位置。
计算机很容易实现这种运算规则,利用 3 个寄存器(2 个具有移位功能)和一个全加器。用一个寄存器存放被乘数,一个寄存器存放部分积的高位,另一个寄存器存放乘数及部分积的低位,再配上加法器及其他相应电路,就可组成乘法器。又因加法只在部分积的高位运行,故不但节省了器材,而且缩短了运算时间。
(2)原码一位乘法
由于原码的表示与真值极为相似,只差一个符号,而乘积的符号又可通过两数符号的逻辑异或求得,因此,上述讨论的结果可以直接用于原码一位乘,只需加上符号位处理即可。
以小数为例,设
[
x
]
原
=
x
0
.
x
1
…
x
n
=
x
0
.
x
∗
,
y
原
=
y
0
.
y
1
…
y
n
=
y
0
.
y
∗
[x]_{原}=x_0.x_1…x_n=x_0.x^*,y_{原}=y_0.y_1…y_n=y_0.y^*
[x]原=x0.x1…xn=x0.x∗,y原=y0.y1…yn=y0.y∗,原码一位乘运算规则如下:
① 乘积的符号位由两原码符号位异或运算结果决定;
② 乘积的数值部分由两数绝对值相乘,同样使用移位的次数来判断乘法是否结束其通式为(小数为例,整数的类似):
由于乘积的数值部分是两数绝对值相乘的结果,故原码一位乘法运算过程中的右移操作均为逻辑右移。
例:已知 x = − 0.1110 , y = − 0.1101 x=-0.1110,y=-0.1101 x=−0.1110,y=−0.1101,求 [ x ⋅ y ] 原 [x \cdot y]_{原} [x⋅y]原。
[
x
]
原
=
1.1110
[x]_{原}=1.1110
[x]原=1.1110,
x
x
x 的绝对值
x
∗
=
0.1110
x^*=0.1110
x∗=0.1110,其符号位
x
0
=
1
x_0=1
x0=1;
[
y
]
原
=
1.1101
[y]_{原}=1.1101
[y]原=1.1101,
y
y
y 的绝对值
y
∗
=
0.1101
y^*=0.1101
y∗=0.1101,其符号位
y
0
=
1
y_0=1
y0=1。
按原码一位乘法运算规则,
[
x
⋅
y
]
原
[x \cdot y]_{原}
[x⋅y]原 的符号位为
x
0
⊕
y
0
=
1
⊕
1
=
0
x_0 \oplus y_0=1\oplus 1=0
x0⊕y0=1⊕1=0。
[
x
⋅
y
]
原
[x \cdot y]_{原}
[x⋅y]原 的数值部分
x
∗
⋅
y
∗
x^* \cdot y^*
x∗⋅y∗ 如下表所示。
故 [ x ⋅ y ] 原 = 0.10110110 [x \cdot y]_{原}=0.10110110 [x⋅y]原=0.10110110 。由上面的例子可知,在进行原码一位乘时,无需在意中间加法过程中发生“溢出”,因为在原码一位乘中,是将数值部分的绝对值相乘,所以根本没有符号位的概念,就算两个以 0 开头的数相加之后的最高位是 1,但逻辑右移后又会变为 0。
(3)补码一位乘法
以小数为例(整数乘法和小数乘法过程完全相同,用逗号代替小数点即可),设被乘数 [ x ] 补 = x 0 . x 1 x 2 . . . x n [x]_{补}=x_0.x_1x_2...x_n [x]补=x0.x1x2...xn, [ y ] 补 = y 0 . y 1 y 2 . . . y n [y]_{补}=y_0.y_1y_2...y_n [y]补=y0.y1y2...yn:
❀ 被乘数 x x x 符号任意,乘数 y y y 符号为正( x , y x,y x,y 指的都是真值)
被乘数
[
x
]
补
=
x
0
.
x
1
x
2
.
.
.
x
n
[x]_{补}=x_0.x_1x_2...x_n
[x]补=x0.x1x2...xn
乘数
[
y
]
补
=
0.
y
1
y
2
.
.
.
y
n
=
y
[y]_{补}=0.y_1y_2...y_n=y
[y]补=0.y1y2...yn=y
则
[
x
⋅
y
]
补
=
[
x
]
补
⋅
[
y
]
补
=
[
x
]
补
⋅
y
[x\cdot y]_{补}=[x]_{补} \cdot [y]_{补}=[x]_{补} \cdot y
[x⋅y]补=[x]补⋅[y]补=[x]补⋅y
与原码乘类似,但加和移位按补码规则运算,乘积的符号自然形成。
❀ 被乘数 x x x 符号任意,乘数 y y y 符号为负
被乘数
[
x
]
补
=
x
0
.
x
1
x
2
.
.
.
x
n
[x]_{补}=x_0.x_1x_2...x_n
[x]补=x0.x1x2...xn
乘数
[
y
]
补
=
1.
y
1
y
2
.
.
.
y
n
=
2
+
y
(
m
o
d
2
)
[y]_{补}=1.y_1y_2...y_n=2+y\ (mod\ 2)
[y]补=1.y1y2...yn=2+y (mod 2),
则
y
=
[
y
]
补
−
2
=
1.
y
1
y
2
.
.
.
y
n
−
2
=
0.
y
1
y
2
.
.
.
y
n
−
1
y=[y]_{补}-2=1.y_1y_2...y_n-2=0.y_1y_2...y_n-1
y=[y]补−2=1.y1y2...yn−2=0.y1y2...yn−1,
x
⋅
y
=
x
(
0.
y
1
y
2
.
.
.
y
n
−
1
)
=
x
(
0.
y
1
y
2
.
.
.
y
n
)
−
x
x \cdot y=x(0.y_1y_2...y_n-1)=x(0.y_1y_2...y_n)-x
x⋅y=x(0.y1y2...yn−1)=x(0.y1y2...yn)−x
故
[
x
⋅
y
]
补
=
[
x
(
0.
y
1
y
2
.
.
.
y
n
)
]
补
+
[
−
x
]
补
[x \cdot y]_{补}=[x(0.y_1y_2...y_n)]_{补}+[-x]_{补}
[x⋅y]补=[x(0.y1y2...yn)]补+[−x]补
所以,将乘数 [ y ] 补 [y]_{补} [y]补 视为一个正数,操作与上面 y y y 符号为正时相同,但最后加 [ − x ] 补 [-x]_{补} [−x]补 校正,乘积的符号位也在运算过程中自然形成。
❀ 被乘数 x x x 符号任意,乘数 y y y 符号任意
Booth 算法。与将 y y y 分符号讨论的计算方法得区别在于,当运算到最后一步时,乘积不再右移,而是根据 y y y 的符号位与数值部分的最高位 y 0 , y 1 y_0,y_1 y0,y1 仅加或减去或不加不减 [ x ] 补 [x]_{补} [x]补。
在进行补码一位乘时,无论是上面哪一种情况,考虑到运算时可能出现绝对值大于 1 的情况(但此刻并不是溢出),故在进行补码加法运算时,部分积和被乘数取双符号位,且进行算数右移操作时,两个符号位都需要进行右移,添补的位与高位符号位相同。
乘法运算分析
前面的笔算乘法改进、原码一位运算、补码一位运算,在理论和计算方法上是行得通的,但是定点计算完成后,其数值部分的位数都扩展为原来的二倍,所以也根本不会发生溢出或者是精度的丢失。
但现实中的机器是做不到这样的,两个定点数相乘得到的数的位数与两数的位数相同。那么使用这种右移 + 加法的方式进行乘法运算时,若最后截取高 n n n 位则会发生精度的丢失。那么结果位数不变的情况下该如何做呢?此时定点整数则需要左移 + 加法,数值部分由高位向低位逐位运算(即与本节讲的方法恰好相反),如果某一步左移时移出的位为 1,则说明发生了溢出。定点小数还是可以使用这节介绍的右移 + 加法,如果右移时移出的位为 1,则说明发生了精度丢失。
本节内容其实讲到笔算乘法可以改进为移位 + 加法就可以结束了,因为后面都是将一个数的位数扩展为两倍,不会溢出,精度也不会丢失,实际意义根本不大。
除法运算(略)
略。
浮点四则运算
浮点加减运算
设两个浮点数
x
=
S
x
⋅
r
j
x
y
=
S
y
⋅
r
j
y
x=S_x \cdot r^{j_x} \\ y=S_y \cdot r^{j_y}
x=Sx⋅rjxy=Sy⋅rjy 由于浮点数尾数的小数点均固定在第一数值位前,所以尾数的加减运算规则与定点数的完全相同。但由于其阶码的大小又直接反应尾数有效值小数点的实际位置,因此当两浮点数阶码不等时,因两尾数小数点实际位置不一样,尾数部分无法直接进行加减。为此,浮点数加减运算必须按以下几步进行。
① 对阶,使两数的小数点位置对齐。
② 尾数求和,将对阶后的两尾数按定点加减运算规则求和(差)。
③ 规格化,为增加有效数字的位数,提高运算精度,必须将求和(差)后的尾数规格化。
④ 舍入,为提高精度,要考虑尾数右移时丢失的精度值。
⑤ 溢出判断,即判断结果是否溢出。
(1)对阶
对阶的目的是使两操作数的小数点位置对齐,即使两数的阶码相等。为此,首先要求出阶差,再按小阶向大阶看齐的原则,使阶小的尾数向右移位,每右移一位,阶码加 1,直到两数的阶码相等为止。右移的次数正好等于阶差,尾数右移时可能会发生数码丢失,影响精度。
阶差计算公式如下:
例:
x
=
0.1101
∗
2
01
,
y
=
(
−
0.1010
)
∗
2
11
x=0.1101 * 2^{01},y=(-0.1010) * 2^{11}
x=0.1101∗201,y=(−0.1010)∗211,求
x
+
y
x+y
x+y。
首先写出
x
,
y
x,y
x,y 在计算机中的补码表示,
x
=
00
,
01
;
00.1101
,
y
=
00
,
11
;
11.1010
x=00,01;00.1101,y=00,11;11.1010
x=00,01;00.1101,y=00,11;11.1010,在进行加法前,必须先对阶,故先求阶差:
[
Δ
j
]
补
=
[
j
x
]
补
−
[
j
y
]
补
=
00
,
01
+
11
,
01
=
11
,
10
[\Delta j]_{补}=[j_x]_{补}-[j_y]_{补}=00,01 + 11,01=11,10
[Δj]补=[jx]补−[jy]补=00,01+11,01=11,10 即
Δ
j
=
−
2
\Delta j=-2
Δj=−2,表示
x
x
x 的阶码比
y
y
y 的小,再按小阶向大阶看齐的原则,将
x
x
x 的尾数右移 2 位,阶码加 2,得
[
x
]
补
′
=
00
,
11
;
00.0011
[x]_{补}^{'}=00,11;00.0011
[x]补′=00,11;00.0011,对阶完毕。
(2)尾数求和
将对阶后的两个尾数按定点加(减)运算规则进行运算。
如上例中的两数对阶后得
[
x
]
补
′
=
00
,
11
;
00.0011
[
y
]
补
=
00
,
11
;
11.0110
[x]_{补}^{'}=00,11;00.0011\\ [y]_{补}=00,11;11.0110
[x]补′=00,11;00.0011[y]补=00,11;11.0110 则
[
S
x
+
S
y
]
补
[S_x+S_y]_{补}
[Sx+Sy]补 为:
即 [ x + y ] 补 = 00 , 11 ; 11 , 1001 [x+y]_{补}=00,11;11,1001 [x+y]补=00,11;11,1001,这不是一个规格化数。
(3)规格化
当基值
r
=
2
r=2
r=2 时,尾数
S
S
S 的规格化形式为
1
2
≤
∣
S
∣
<
1
\frac{1}{2} \leq |S| < 1
21≤∣S∣<1 其是否为规格化数的判断方法如下:
对于原码,不论正数还是负数,第一位为 1 则表示规格化数;对于补码,符号位与第一位不同则表示规格化数。
但是对于
S
<
0
S<0
S<0,有两种情况需特殊处理:
①
S
=
−
1
2
S=-\frac{1}{2}
S=−21,则
[
S
]
补
=
1.100...0
[S]_{补}=1.100...0
[S]补=1.100...0。此时对于真值
−
1
2
-\frac{1}{2}
−21 而言它满足规格化数(
∣
S
∣
=
1
2
|S|=\frac{1}{2}
∣S∣=21),但对于补码的判别方法而言它不是规格化数(此时符号位与第一位相同)。为了便于硬件判断,特别规定
1
2
\frac{1}{2}
21 不是规格化的数(对补码而言)。
②
S
=
−
1
S=-1
S=−1,则
[
S
]
补
=
1.00...0
[S]_{补}=1.00...0
[S]补=1.00...0。因小数补码允许表示 -1,特别规定 -1 视为规格化的数(对补码而言)。
当尾数求和(差)的结果不是规格化数时,则需规格化,规格化又分为左规和右规两种(补码):
-
左规:当尾数出现 00.0 × × × 00.0××× 00.0××× 或 11.1 × × × 11.1××× 11.1××× 时,需要左规。尾数左移一位,阶码减 1,直到数符和第一位数不同为止。
如上例中的求和结果 [ x + y ] 补 = 00 , 11 ; 11 , 1001 [x+y]_{补}=00,11;11,1001 [x+y]补=00,11;11,1001,不是规格化数,需左规,即将其左移一位,同时阶码减 1,得 [ x + y ] 补 = 00 , 10 ; 11 , 0010 [x+y]_{补}=00,10;11,0010 [x+y]补=00,10;11,0010,即 x + y = ( − 0.1110 ∗ 2 10 ) x+y=(-0.1110 * 2^{10}) x+y=(−0.1110∗210)。
-
右规:当尾数出现 01. × × × 01.××× 01.××× 或 10. × × × 10.××× 10.××× 时,表示尾数溢出,这在定点加减运算中是不允许的,但在浮点运算中这不算溢出,因为可通过右规处理。右规时尾数右移一位,阶码加 1。
例:已知两浮点数
x
=
0.1101
∗
2
10
,
y
=
0.1011
∗
2
01
x=0.1101 * 2^{10},y=0.1011 * 2^{01}
x=0.1101∗210,y=0.1011∗201,求
x
+
y
x+y
x+y。
解:
x
,
y
x,y
x,y在机器中以补码表示为
[
x
]
补
=
00
,
10
;
00
,
1101
[
y
]
补
=
00
,
01
;
00
,
1011
[x]_{补}=00,10;00,1101 \\ [y]_{补}=00,01;00,1011
[x]补=00,10;00,1101[y]补=00,01;00,1011 ① 对阶
[
Δ
j
]
补
=
[
j
x
]
补
−
[
j
y
]
补
=
00
,
10
−
00
,
01
=
00
,
01
[\Delta j]_{补}=[j_x]_{补}-[j_y]_{补}=00,10 - 00,01=00,01
[Δj]补=[jx]补−[jy]补=00,10−00,01=00,01 这表明
y
y
y 的阶码比
x
x
x 的要小,根据小阶向大阶看齐的原则,
y
y
y 的尾数右移 1 位,阶码加 1,即
[
y
]
补
′
=
00.10
;
00.0101
[y]_{补}^{'}=00.10;00.0101
[y]补′=00.10;00.0101(精度损失)
② 尾数求和
③ 右规
上面的计算结果为
[
x
+
y
]
补
=
00
,
10
;
01
,
0010
[x+y]_{补}=00,10;01,0010
[x+y]补=00,10;01,0010
右规后
[
x
+
y
]
补
=
00
,
11
;
00
,
1001
[x+y]_{补}=00,11;00,1001
[x+y]补=00,11;00,1001(注意连同溢出的符号位一起移位),所以
x
+
y
=
0.1001
∗
2
11
x+y=0.1001 *2^{11}
x+y=0.1001∗211。
(4)舍入
在对阶和右规过程中,可能出现尾数末位丢失,引起误差。为此可用舍入法来提高尾数的精度,常用的舍入法有以下两种:
- 0 舍 1 入 法。在尾数右移时,被移去的尾数末位为 0,则舍去;被移去的最高数值位为 1,则在尾数的末位加 1。这样做可能使尾数又溢出,此时需再做一次右规。
- 恒置 1 法。尾数右移时,不论丢掉的最高数值是 1 还是 0,都使右移后的尾数末尾恒置 “1”。这种方法同样有使尾数变大和变小的两种可能。
综上所述,浮点加减运算经过对阶、尾数求和、规格化和舍入等步骤,与定点加减运算相比,显然要复杂得多。
(5)溢出判断
与定点加减法一样,浮点加减运算最后一步也需判断溢出。在浮点规格化中已指出,当尾数之和(差)出现 01. × × × 01.××× 01.××× 或 10. × × × 10.××× 10.××× 时,并不表示溢出,只有将此数右规后,再根据阶码来判断浮点数运算结果是否溢出。
阶码 [ j ] 补 = 01. × × × [j]_{补}=01.××× [j]补=01.××× 为上溢;阶码 [ j ] 补 = 10. × × × [j]_{补}=10.××× [j]补=10.××× 为下溢,按机器零处理。
浮点乘除法运算(略)
略。
算数逻辑单元
针对每一种算术运算,都必须有一个相对应的基本硬件配置,其核心部件是加法器和寄存器。当需要完成逻辑运算时,势必需要配置相应的逻辑电路,而 ALU 电路是既能完成算术运算又能完成逻辑运算的部件。
本BLOG上所有的原创文章未经本人许可,不得用于商业用途及传统媒体。网络媒体转载请注明出处,否则属于侵权行为:
https://blog.csdn.net/qq_39583450/article/details/114607570