第二章 数据的表示和运算
2.1 K进制
常用的进制为二进制(B)、八进制(O)、十进制(D)和十六进制(H),在十六进制中,A表示10,B表示11以此类推。
每个进制有一个代表字母,比如A832CF表示的是16进制表示的A832C,256D表示十进制下的256
各个进制之间相互转换如下
另外还可以使用除基取余法
该法可以处理任意r进制的转换
2.2 定点数
使用最高位作为符号位,0为正1为负,可以用于表示整数或者小数,用定点数表示小数被称为定点小数。小数点位于符号位后面,只能表示绝对值在1以内的小数。
1.无符号数
和一般的定点数不一样,没有正负之分,表示数的绝对值。整个数的所有二进制位都是数值位,没有符号位。n位无符号数表示的范围为0~2n-1。无符号数没有小数。
2.原码、反码、补码和移码
原码
原码如上述定点数一样,有符号位,并且可以表示定点整数和定点小数。虽然原码非常直观友好,但是也有一个很大的缺点,就是无法将减法转换成加法运算。
- 原码的整数表示范围是 − ( 2 n − 1 ) ≤ x ≤ 2 n − 1 -(2^n-1)\leq x\leq 2^n-1 −(2n−1)≤x≤2n−1,原码有两种表示0的方法,分别是1,0000000和0,0000000。
- 原码的整数表示范围是 − ( 1 − 2 − n ) ≤ x ≤ 1 − 2 − n -(1-2^{-n})\leq x\leq 1-2^{-n} −(1−2−n)≤x≤1−2−n
反码
反码的运算规律如下:如果符号位为0,则反码和原码一致;如果符号位为1,则反码数值位和原码相反。反码没有实际应用,是原码转化为补码的一种中间状态。
补码
补码的设计思想可以用以下例子比喻:将一个指向10点的闹钟拨到8点,可以将它逆时针拨2格,类似于减法;也可以顺时针拨10个格,也可以。而这种顺时针拨10格,使得时针越过12点,重新计数的思想,就是补码的思想。
对于补码来说。符号位为0的时候,补码和原码相同,也就是正数的补码数值上和原码一致;符号位为1的时候(也就是负号的时候),负数的补码=反码末位+1,也就是原码数值位取反加一。补码求原码也是和上面一样。
- 在将2种原码的0的表示1,0000000和0,0000000转化为补码后都是0,0000000,也就是在补码中只有一种0的标识
- 在定点整数补码中,规定1,0000000表示27,则n+1位补码的表示范围是 − 2 n ≤ x ≤ 2 n − 1 -2^n\leq x\leq2^n-1 −2n≤x≤2n−1,比原码多一个-2n
- 在定点小数补码中,规定1.0000000表示-1,则n+1位补码小数的表示范围是
−
1
≤
x
≤
1
−
2
−
n
-1\leq x\leq 1-2^{-n}
−1≤x≤1−2−n
移码
在补码的基础上将符号位取反,移码只能用于表示整数。移码能够十分方便地对比两个机器数的大小
3.移位运算
假设当前数字是用r进制表示的
右移动n位:除以r的n次方
左移n位置:乘以r的n次方
算术移位
在有符号数中
左移动、右移动都补0,符号位不参与移位
而且如果左移动丢1,运算会出错;右移动丢1,则会影响精度,结果相差不大
补码、反码的情况:
反码的算术移位
对于反码的算术移位——正数的反码和原码相同,因此移位运算也相同
对于负数反码的算术移位,由于1和0的表示意义刚好和原码相反,因此:右移则高位补1,低位舍弃;左移则低位补1,高位舍弃
补码的算术移位
正数补码的算数移位同原码保持一致
负数补码=反码的末位加一。这导致反码最右边的连续的1都会因为进位而变为0,直到进位遇到了第一个0为止。
因此在负数的补码中,最右边的1及其右侧的数字和原码是一致的;最右边的1左边的数字是和反码保持一致的。因此负数补码需要以下规则:
- 右移同反码一样,高位补1,低位舍弃
- 左移同原码一样,低位补0,高位舍弃
计算机乘法
对于-20,进行-20x(20+21+22)运算就可实现-20x7的效果,其中20是不移位,21是左移一位,22是左移两位,这就是计算机中的乘法,通过加法和算术移位实现
逻辑移位
在无符号数中
左移动:高位丢弃,低位添0
右移动:低位丢弃,高位添0
应用:生成RGB值
循环左移:数值位的最高位移动到最低位,其他数字左移一位
带符号位的循环左移
应用:大端存储到小端存储的转换
4.定点数运算
对于带有符号位的原码运算,如果对两个带符号位的,一正一负的原码进行直接相加,得出来的结果将会是错误的。计算机对原码进行运算的时候需要特殊处理,也就是将”正数加负数“转换为”正数减正数“,但是这种特殊处理又需要增加特殊的减法器电路来处理,将会十分麻烦。
例子:对两个带符号位的,一正一负的原码进行直接相加得出错误结论
两个数的加法会有到加法器,这点是易于实现的。但是减法器十分难以设计,电路也很复杂。于是人们在想能不能将两个数的减法转化为两个数为加法,那么计算机就只需有加法器就行
模运算
为了统一计算机中的加减运算,人们试图使用加法来替代减法,使得计算机中的加减法运算都转化为加法运算,其中需要使用的就是模运算:
其中显著规定mod运算的结果必定大于等于0,例子如下:
−
3
=
(
−
1
)
∗
12
+
9
⇒
(
−
3
)
m
o
d
12
=
9
-3 = (-1)*12+9 \Rightarrow (-3)mod12 = 9
−3=(−1)∗12+9⇒(−3)mod12=9
9
=
0
∗
12
⇒
9
m
o
d
12
=
9
9=0*12\Rightarrow 9mod12=9
9=0∗12⇒9mod12=9
−
15
(
−
2
)
∗
12
⇒
−
15
m
o
d
12
=
9
-15(-2)*12\Rightarrow -15mod12=9
−15(−2)∗12⇒−15mod12=9
也就是在mod 12运算下,-3、9、21、33、-15都等价,都是9
统一加减法
我们通过上述例子可以看到,[10+(-3)]mod12和[10+9]mod12的结果是一样的,都是7,因此这使得10-3这个减法操作转化成了[10+9]mod12这个加法操作
上述例子中-3和9是一对补数,互补的两个数的绝对值之和等于模,也就是在实际的计算机运算中,如果是正数加复数操作,则对于a来说: 模 − ∣ a ∣ = a 的 补 数 模-|a|=a的补数 模−∣a∣=a的补数,其中a的补数必定是正数,因此可以用加法代替减法
由于计算机中的运算器是有位数限制的,比如说8进制的加法器中,数的表示范围是0-255,任何超出255的部分都会被抛弃,因此他的模就是28=256,任何在此加法器中进行的运算最后都会进行mod 256的操作。而求一个数的补数也很简单,就是该数字的补码。而且加法运算的时候是符号位也参加运算的
因此我们可以知道,使用补码可以将减法操作转化为等价的加法操作,执行加法操作时符号位可以一起参加运算,大大统一了计算机中运算的规律,不需要考虑符号位的特殊性,ALU中也无需集成减法器
加减运算详解
但是原码的加减法用机器电路实现不太方便,一般不会用这种实现
正+正和负+负这两种情况可能会出现溢出
在计算机中,加减运算一般两个数都采用补码来进行运算,
[
A
+
B
]
补
=
A
补
+
B
补
[A+B]_补=A_补+B_补
[A+B]补=A补+B补
在计算机中,将[y]补转化为[-y]补的方式是:先将数字全部按位取反得到反码,然后在将数字传入到ALU的时候,将最低位的进位设为1,那么在进行运算的时候,会将反码进行加一操作,从而得到补码
溢出判断
在A=15的情况下
上面这种情况就是溢出
溢出分为两种情况,分别是上溢出和下溢出,只有正数加正数才会上溢出,只有负数加负数才会下溢出
发生了上溢出后,正数的最高位丢失,导致变为负数;而发生下溢出后,负数的最高位丢失,变成正数。如果正数加正数得出的结果是负数,而负数加负数得出的结果是正数,那么可以断定发生了溢出
方法一:采用一位符号位
设A的符号为As,B的符号位为Bs,运算结果的符号为Ss,则溢出逻辑表达式为
V
=
A
s
B
s
S
s
‾
+
A
s
‾
B
s
‾
S
s
V=A_sB_s\overline{S_s}+\overline{A_s}\overline{B_s}S_s
V=AsBsSs+AsBsSs
V=0表示无溢出;V=1表示有溢出
TIPS:ABC表示A与B与C,只有A、B、C都是1的时候,ABC才为1;A+B+C表示A或B或C,只要其中有1个1,结果就为1;
A
‾
\overline A
A表示非运算
也就是,当两个加数为正,但是结果为负的时候,
A
s
‾
B
s
‾
S
s
=
1
\overline{A_s}\overline{B_s}S_s=1
AsBsSs=1,则会导致V=1;当两个加数为负,但是结果为正的时候,
V
=
A
s
B
s
S
s
‾
=
1
V=A_sB_s\overline{S_s}=1
V=AsBsSs=1,从而导致V=1
方法二:采用一位符号位,根据数据位的进位情况判断溢出
该法是针对补码来说的
符号位进位Cs | 最高数值位的进位C1 | |
---|---|---|
上溢出 | 0 | 1 |
下溢出 | 1 | 0 |
如果Cs异或C1为0则没有溢出,反之择优
方法三:采用双符号位(最常考)
正数符号为00,负数符号为11
单符号位又称为模二补码;双符号位又称为模四补码。存储双符号位的时候实际上只存储一个符号位,运算时会复制一个符号位。
符号扩展
2.3 乘除运算
一、原码乘法
在计算机中,0.211乘以0.985的操作被简化为了:
(
0.985
×
1
×
1
0
−
6
)
+
(
0.985
×
1
×
1
0
−
5
)
+
(
0.985
×
1
×
1
0
−
4
)
(0.985 \times 1\times 10^{-6})+(0.985 \times 1\times 10^{-5})+(0.985 \times 1\times 10^{-4})
(0.985×1×10−6)+(0.985×1×10−5)+(0.985×1×10−4)
二进制例子如下:
可以看到,第一个乘数每次要么就是乘以1,要么乘以0。因此简化了运算。而后面的位积2n只需要使用移位运算就可以实现。
对于符号位的处理只需要对符号位使用异或运算,就可以得出结果的符号位:也就是只有两个乘数都是同号的时候,符号位才会是0。
需要使用到的寄存器
需要使用到ALU算术逻辑单元,其中的ACC负责存储乘积高位;MQ负责存储乘数和乘积低位;通用寄存器单元X用于存储被乘数
还有一个就是溢出问题,两个n位(不考虑符号位)的二进制数相乘,最多可以产生2n位的二进制数,因此单个寄存器是无法存下数乘结果的。因此,我们将ACC寄存器和MQ寄存器一同用来存放数乘结果。其中ACC存放高位的部分,MQ存放低位的部分。
刚开始,MQ存储乘数,X存储被乘数,ACC需要先清零:
- 取出MQ中的最低位,也就是最右边的位
- 如果最低位为1则ACC加上X中的被乘数,也就是最低位为1时执行 ( A C C ) + ( X ) → A C C (ACC)+(X)\to ACC (ACC)+(X)→ACC
- 当前位已经使用完毕,以后也不需要使用了,因此ACC和MQ整体向右逻辑移位一位,这时候最低位因右移被抛弃。
- 重复上述过程,直到MQ中的乘数的数值位全部被抛弃,那么此时MQ中存放的信息就是乘数结果的低位,ACC中是乘数结果的高位。(注意:两个乘数的符号位不参与此过程,符号位的运算是单独运算的)
二、补码乘法
在补码中,MQ寄存器会有一位额外的辅助位,辅助位初始为0,每次右移会使得MQ的最低位顶替原来的辅助位
好吧笔者是在不知道如何形容
和原码乘法的对比
原码乘法 | 补码乘法 |
---|---|
进行n轮加法和移位 | 进行n轮加法和移位,最后再多用一次加法 |
每次加法可能+0或者+|x| | 每次加法可能+0、+x的补码或者-x的补码 |
每次移位是逻辑右移 | 每次移位是补码的算数右移 |
符号位不参与运算 | 符号位参与运算 |
三、原码除法
设机器字长为5位,含一位符号位,x=0.1011,y=0,1101,求x/y,则二进制除法运算过程如下
可以看到,每次运算只需要对比当前余数和除数的大小:如果余数较大,则当前位取1;如果除数比较大,则当前位取0。直到确认了5位商就可以停止了(因为机器字长是5位)
在源码除法中,需要用到算术逻辑单元ALU,其中的ACC存储器用于存储被除数和余数,MQ存储器用于存储商,通用寄存器X用于存储除数
第一种:恢复余数法
此法用于处理定点小数,要求被除数一定要小于除数,才能保证其商小于1,因为定点小数无法表示商大于1的数。
符号位单独处理,只需要对被除数和除数的符号为进行异或运算就可以得出运算结果的符号
数值位则参与直接运算,相当于直接取两个除数的绝对值进行运算,运算结束后再加上符号位。另外运算开始前需要四个数据,分别是|x|,|y|,[-|y|]补,[|y|]补
运算器会默认当前位可以商1,将
(
A
C
C
)
−
(
除
数
)
→
A
C
C
(ACC)-(除数)\to ACC
(ACC)−(除数)→ACC,也就是
(
A
C
C
)
+
[
−
∣
y
∣
]
补
→
A
C
C
(ACC)+[-|y|]_补\to ACC
(ACC)+[−∣y∣]补→ACC如果发现ACC中的数值的符号位为1,也就是为负数,证明当前被除数不足以商1,那么就会将MQ中当前位的商改为0,并且由于是商0,所以被除数并没有-除数,应该将ACC值恢复为原样,也就是
A
C
C
+
[
∣
y
∣
]
补
→
A
C
C
ACC+[|y|]_补\to ACC
ACC+[∣y∣]补→ACC。此时ACC恢复为原值。
这就是恢复余数法的思想,计算机尝试在当前位商1,如果发现商1后得到的余数为负数,那么就将当前位换为商0,并且将余数恢复到商0的状态。
接下来ACC和MQ集体向右逻辑左移一位,ACC的高位被丢弃,MQ的低位补一个0,此时被除数往下移动一位,商也移动一位。
商已经和机器字长一样长之后,运算完毕,此时ACC里的就是余数。最后我们再添加小数点并且确认符号位。
对n位小数,需要进行n次左移,上商n+1
第二种:加减交替法
此法用于处理定点小数,要求被除数一定要小于除数,才能保证其商小于1,因为定点小数无法表示商大于1的数。
加减交替法最主要是优化恢复余数法的恢复余数的部分。
我们再看回恢复余数法的恢复余数的流程,设余数为a,[|y|]补=b,商1后发现余数x=a为负数,那么应该商0,并且恢复余数,也就是
(
A
C
C
)
+
[
∣
y
∣
]
补
→
A
C
C
(ACC)+[|y|]_补\to ACC
(ACC)+[∣y∣]补→ACC,ACC中的余数=a+b,接着进行逻辑左移,相当于ACC中的值乘以2,等于(a+b)*2,左移完成后,再次尝试商1,也就是
(
A
C
C
)
+
[
−
∣
y
∣
]
补
→
A
C
C
(ACC)+[-|y|]_补\to ACC
(ACC)+[−∣y∣]补→ACC,此时ACC中的余数减去b,相当于2a+b。
可以看到,如果出现了不足以商1的时候,可以直接执行 2 A C C + [ ∣ y ∣ ] 补 → A C C 2ACC+[|y|]_补\to ACC 2ACC+[∣y∣]补→ACC。也就是当余数为负数的时候商0,并且对余数进行左移再+|除数|
对于n位小数,加减需要进行n+1次或n+2次(最后余数若为负数,还需要多一次加),每次加减确定一位商,需要左移n次
四、补码除法
此法用于定点数补码除法,和原码的加减交替法类似,但是符号位会参与运算。
五、强制类型转换
C语言中的定点整数都是用补码存储的。
无符号数和有符号数类型转换并不会改变二进制内容,只会改变他的解释方式
比如
short x=-4321;
unsigned short y = (unsigned short)x;
// x=-4321,y=61215
长整数变为短整数,则会进行高位截断,保留低位。
短整数变为长整数,则进行符号扩展:对于补码,则在新扩展的高位添加1,真值不变。
六、数据的存储
大小端模式
边界对齐
需要知道给出字节、半字、字这三者中的其中一个的编号,然后转换为其他两个的编号
2.3 运算方法和运算电路
1.算术逻辑单元ALU
算术逻辑单元的主要功能包括:
- 算术运算:加减乘除
- 逻辑运算:与、或、非、异或
- 辅助功能:移位、求补
ALU结构
输入和输出信号的位数很大程度上决定了电脑的机器字长
基本逻辑运算及其门电路
优先级:与运算>或运算
- 与非:只有变量全部为1的时候,函数才为1
- 或非:只有变量全部为0的时候,函数才为1
- 异或= A ‾ ⋅ B + A ⋅ B ‾ \overline A\cdot B+A\cdot \overline B A⋅B+A⋅B,A、B值相同则为0,A、B值不同则为1,扩展:有奇数个变量值为1,则函数为1;有偶数个变量值为0,则函数为0
- 同或:A、B值相同则为1,A、B值不同则为0,是异或的取非。
- 应用:奇偶校验吗(用异或实现)
2.一位全加器
3.串行加法器和并行加法器
串行加法器
并行加法器
第一种:串行进位的并行加法器
第二种:并行进位的并行加法器
并行进位的并行加法器中,各级进位信号同时形成,又称为先行进位,同时进位
第三种:并行进位的并行加法器的优化
并行进位的并行加法器在位数变多的时候,内部电路设计会变得很复杂
单级先行进位方式,又称为组内并行,组间串行的进位方式,优点是简化了电路设计,缺点是在组间需要采用串行进位
多级先行进位方式,又称为组内并行、组间并行进位方式。特点是将单个加法器穿省的进位信号输入到一个统一的CLA电路中处理
4.ALU的优化
2.4 浮点数
一、基本组成
浮点数相对于顶点数,能够用相对少的位数表示相对打的范围。
浮点数分为阶码和尾数两部分表示,阶码反应浮点数的表示范围,尾数表示浮点数的精度。
在浮点数的表示中,阶码中用逗号区分符号位,用分号区分阶码和尾数两个部分,比如a=0,01;1,1001表示-0.111
尾数的数值最高位尽量是非零的,因为这能够提高精度,这种浮点数称为规格化浮点数。规格化浮点数就是调整一个飞规格化浮点数的尾数和阶码,是的非0浮点数在尾数的最高位上保证是一个有效值。
但是单符号位的信息是丢失的,溢出不可挽救。另外需要注意浮点数是用补码表示还是用原码表示的,其算数左移和右移的规则不一样。
规格化浮点数的特点
可以看到,二进制的表示范围的绝对值有上限也有下限
二、IEEE 745标准
用于规定浮点数的阶码和尾数的位数的标准,从而使得计算机之间交换浮点数可以通用
IEEE745需要用到移码,移码的定义是移码=真值+偏置值。偏置值一般取2n-1。但是在IEEE745中,使用到的移码稍有不同,其偏置值一般取2n-1-1,那么它的移码数值表和偏置值为2n-1的对比如下:
总之,偏置值为2n-1-1的移码的全0和全1的移码分别表示-127和-128,其余移码代表的数值比偏置值为2n-1的移码多1。
数符用来表示整个浮点数的正负。
短浮点数中,尾数部分使用原码表示的,由于IEEE754必是规格化浮点数,所以其最高位必然为1,因此可以不用表示出来,所以尾数序列会隐藏最高位的1,假设位数序列为M,那么实际上的尾数序列为1.M。
另外,IEEE 754标准中的短浮点数阶码的表示范围为-126-127,因为-127,-128对应的移码为全零和全一,有着特殊用途 。
因为阶码使用移码表示,要确认阶码的真值,需要使用阶码E-偏置值=真值。其中在IEEE 754中偏置值为2n-1-1
举例
IEEE754标准的浮点数的表示范围
可以看到,在IEEE754中,规格化短浮点数的真值为 ( − 1 ) S × 1. M × 2 E − 127 (-1)^S\times 1.M\times 2^{E-127} (−1)S×1.M×2E−127,规格化长浮点数的真值为 ( − 1 ) S × 1. M × 2 E − 1023 (-1)^S\times 1.M\times 2^{E-1023} (−1)S×1.M×2E−1023
三、浮点数计算
看ppt