计算机组成原理

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

#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
int main() {
while (1) {
uint8_t val, res1, res2;
if (1 == scanf("%hhd", &val)) {
res1 = 255 - val + 1; //这里用255+1而不是256还有一个原因就是假如机器字长为8位,最大只能表示255
res2 = (~val) + 1;
assert(res1==res2);
printf("255 - x + 1 \t:%hhd\n(~val) + 1 \t:%hhd\n", res1, res2);
}
while ('\n'!=getchar())
continue;
}
}

上面的代码,对于-128(1000 0000)的结果仍然是-128(1000 0000),应为8bit最大只能表示127,有时可能会引发某些安全漏洞

补码的逆向思考过程

按照一个字节来说,我们想要-1 + 1 = 0,即 0000 0001+?=0

只要?满足了等于0我们就可以认为这个?就是-1,我们可以通过溢出来的到0

   0000 0001----> +1
+ 1111 1111----> -1
1 0000 0000----> 0

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
BHS IndexOutOfBounds;HS:unsigned high or same,大于或等于就跳转,即X20符号位为1 或者 符号位为0且大于时才跳转

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/