计算机组成原理
cpu性能
时钟周期长度(clock period): 每个时钟周期的时间长度
时钟周期数(clock cycle): 以时钟周期长度为单位
CPI(Clock cycles Per Instruction) 表示执行每条指令所需的平均时钟周期数
MIPS(Million Instructions Per Second) 每秒百万条指令
$$性能=\frac{1}{执行时间} $$
$$时钟周期长度=\frac{1}{时钟频率}$$
$$程序的CPU执行时间 = 程序的指令数 \times每条指令的平均时钟周期数CPI \times 时钟周期长度$$
$$MIPS=\frac{指令数}{指令时间\times10^6}=\frac{指令数}{指令数\times CPI \times 指令周期长度\times10^6}=\frac{1}{CPI\times指令周期长度\times10^6}=\frac{时钟频率}{CPI\times10^6}$$
补码$\infty$思考
计算机有整数符号数为什么不用符号及值表示法而是补码
- 会浪费1bit内存,比如有+0和-0两个0
- 它的加、减法运算分别用加法器和减法器实现增加硬件设计复杂性 比如1字节中+1: 0000 0001 ,-1: 1000 0001,z则(+1)+(-1)如果单纯用加法器则得到1000 0010: -2,emm,如果想得到正确结果需要cpu修正
- 补码可以解决上述问题,符号及值表示法主要用于浮点数中
求补码的运算为什么会是各位取反加1?
n位2进制运算中,数P的补数Q则有 $ P + Q = 2^{n}$
求n位二进制数N的补就变为了 $2^n-N=2^n-1-N+1$
其中$2^n-1-N=11…1-N$ 对于N的第 i 位 ni 来说就相当于取反,$1-n_i=\overline{n_i}$
所以就相当于对N各位取反加1
|
上面的代码,对于-128(1000 0000)的结果仍然是-128(1000 0000),应为8bit最大只能表示127,有时可能会引发某些安全漏洞
补码的逆向思考过程
按照一个字节来说,我们想要-1 + 1 = 0,即 0000 0001+?=0
只要?满足了等于0我们就可以认为这个?就是-1,我们可以通过溢出来的到0
0000 0001----> +1 |
emm,高位1溢出,得到0,这样把最高位当作符号位
所以非负数只能用最低7位表示$[0,2^7-1]$,负数则为$[-2^7,-1]$
对于n位二进制就是$[-2^{n-1},2^{n-1}-1]$
个人认为补码提供了一种加减法统一按照无符号数加法运算的机会,根据解释方法的不同,赋予运算过程和结果不同的意义,降低硬件设计的复杂度
对于一个数求两次补码会是它本身
这也和我们认知里的$-(-A)=A$符合,可以利用这个特性快速的求解负数补码表示的数值,比如求符号位为1的补码A,他是正数B的补码,所以对A再次求补,就会得到B,A就是-B
补码(有符号数)加减法溢出
设A的符号位为a,B的符号为B,A+B符号为s
是否溢出判断标准$Overflow=\overline{a}\overline{b}s+ab\overline{s}$
- 两个正数相加,结果为负数,溢出
- 两个负数相加,结果为正数,溢出
- 整数和负数相加(即减法)不可能溢出,因为和不可能大于其中任何一个操作数
边界检测的简便方法
将有符号数看作无符号数来处理
比如,对于大小X11的数组,索引X20的边界检查需要不满足X20>=X11 or X20<0
SUBS XZR,X20,X11 |
arm里cmp就是用SUBS XZR,X1,X2实现的
但是这里BHS需要carry位==1跳,即carry==1代表X20>=X11,和X86正好是相反的
猜测原因是因为SUBS XZR,X1,X2 = X1 + not(X2) + 1 用加法器来实现,也符合大于等于的结果(等于就是正好溢出时的情况)
浮点$\infty$思考
之前有讨论过iee754两个比较有意思的事情
浮点数表示及传参: https://grxer.gitee.io/2023/04/17/An-interview-question-from-baidu/
浮点数运算误差及减小: https://grxer.gitee.io/2023/04/23/floating-point-calculation-and-kahan/