4. 从 C 语言到 汇编指令
位数扩展
有符号数的符号位(most significant number)为 1 时,扩展时高位补 1
有符号数的符号位(most significant number) 为 0 时,扩展时高位补 0
无符号数的扩展时高位补 0
寄存器知道存储数值是有符号还是无符号的吗
答案是不知道,寄存器只会存储数值,不会存储数值的符号,符号是由汇编码的不同操作指令来决定的,比如 LDURSW 就是有符号数,LDUR 就是无符号数
例子
比如将一般的 int 进行 bit shift, 那么 1 >> 2 = 0, 而 -1 >> 2 = -1
数字存储顺序
Endian 这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian(这句话最为形象)。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开
注:存储顺序是内存的,寄存器没有这个说法!
一般来 ...
2. lc-2k 指令集架构
硬件结构
32 位 处理器: 指令长度是 32 位 , 寄存器大小是 32 位
32 位处理器的关键特征是其寄存器、数据总线和地址总线的宽度为 32 位。这意味着它可以处理 32 位的整数,并且通常可以寻址的最大内存空间为 4 GB。
在 32 位处理器中,寄存器和数据路径通常也是 32 位的,所以处理器可以在一次操作中处理 32 位的数据
其指令长度也是 32 位(这里的32 没有特指王楚钦)
8 个寄存器,其中 reg 0 一般只会被赋值 0
内存寻址范围 4GB 即 65536 words
指令形式
寄存器型指令结构
31 - 25
24 - 22
21 - 19
18 - 16
15 - 3
2 - 0
unused
opcode
regA
regB
unused
destR
立即数型指令结构
31 - 25
24 - 22
21 - 19
18 - 16
15 - 0
unused
opcode
regA
regB
offset
J 类型指令 (jalr)
31 - 25
24 - 22
21 - 19
18 - 16 ...
3. ARM 指令集架构
相比于前一节课讲的 lc2k isa, arm 架构的效果会好很多
ISA 的分类
RISC 架构,Reduced Instruction Set Computing
指令数量更少,编码的指令长度是一致的,硬件设备相对更加简单,程序更大,手写会更加困难,但是当前非常常用
应用: lc2k, risc-v, arm (包括其子集 LEG)
CISC 架构,Complex Instruction Set Computing
用更多、更复杂的指令集,编码的指令的长度是不一定的,所以硬件更复杂,程序的长度更短,手写更方便,现在比较少用了
应用: x86
指令及其分类
算术指令 Arithmetic
格式:3 operand fields, 一般会将 destination 寄存器放在第一位
ADD X1, X2, X3: 将 X2 + X3 的结果转存到 X1 寄存器中
这个和 lc2k 是反的
只能操作于
ARM 指令集存储形式
| opcode | Rm | shamt | Rn | Rd | 存储了一个指令集
其中 Rm 表示第二个 register operand, Rn 表 ...
3. 随机变量与概率分布
随机变量 Random Variable (RV)
一个变量,可以被赋予一个 sample space 中的值,常常用 XXX 表示
可以被分为 连续的或者 离散的(也可能是混合)
离散 表示可能的值是有限的或者 countable 的
分布 distribution 表示选中的值随着概率的变化
概率质量函数 probability mass function (pmf)
离散变量的独有特性,符号一般为 p, 公式
p(x)=P(X=x)p(x) = P(X = x)
p(x)=P(X=x)
性质
∑p(x)=1\sum p(x) = 1∑p(x)=1
p(x)≥0p(x) \ge 0p(x)≥0
累计分布函数 cumulative distribution function (cdf)
可以是离散或者连续变量的函数,符号 FFF, 表示小于等于 xxx 值的可能性积累量
F(x)=P(X≤x)F(x) = P(X \le x)
F(x)=P(X≤x)
离散的cdf 是一个 step function
均值 mean
一般用 μ\muμ 表示 population mean, 用 ...
5. 递归算法
尾递归 Tail Recursion
我们称递归调用在函数最后一步的递归方式为 尾递归
例如我们在计算阶乘的时候,如果我们这样写:
1234def factorial(n, acc=1): if n == 0: return acc return factorial(n-1, acc*n)
那么调用自身的步骤在最后,就是尾递归,这种递归形式由于和 正向递推没有很大的区别,有一些编译器会将其变成 iteration 的形式进行执行,从而避免 stack-overflow 的问题,其占用的时间和空间都会比一般的递归小很多
递归与压栈操作
在函数被调用的时候,我们称一个本地变量存储在名为 program stack 的栈结构中
在调用函数之后,其arguments 会被 push onto program stack
在函数执行完之后,arguments 就会被 pop 出栈
在函数中执行 return, 返回值会被push 到 prog stack 中
如果 return 的值被收到,那么返回值会被 pop 走,且本地变量会被重新存储
函数栈可以被嵌套 (nes ...
4. 程序性能的分析
时间的测量
1234567891011#include <chrono>int main(){ Timer t; t.start(); t.stop(); cout << t.seconds() << endl; t.reset(); t.start(); t.stop();}
但是多次查看系统时间会导致程序明显变慢
常用的工具 profiling tools
perf 指令会显示某些节点花费的时间、cpu占用等性能
或者在linux 下,可以考虑使用 time prog 指令,该指令会在命令行输出一行 后面的prog 内容加上 各个部分占用的时间以及cpu占用量
11.60s user 0.03s system 95% cpu 1.711 total
user: 程序占用时间
system: 系统执行该程序使用的额外时间
elapsed: 从开始打表到结束打表所经过的时间差,会包含期间其他进程占用的时间
cpu: 程序的 cpu 占用量,计算公式 user+system/elapseduser + system / elaps ...
6. 动态规划 Dynamic Programming
在分治算法中,我们已经知道要将一个问题分裂成不同的子问题来解决,但是,如果有些时候子问题之间存在覆盖问题,那么再利用 分治算法得到的时间复杂度就会非常大,所以,我们往往使用制表法来解决这个问题,中文名“动态规划”。
动态规划的解 ( OP, optimal)往往有很多个, 但是我们会用 value 进行标注这个 解,即我们可以通过比较 value 来找到最优解 (OTV, optimal value)。
从斐波那契讲起
如果我们要求解斐波那契数列中第 n 个数,那么我们可以用递归 (Top-Down) 的方法:
123456def fib(n): if n == 0: return 0 if n == 1: return 1 return fib(n-1) + fib(n-2)
但是这个方法的时间复杂度是 O(2n)O(2^n)O(2n),时间表达式 T(n)=T(n−1)+T(n−2)+O(1)T(n) = T(n-1) + T(n -2)+ O(1)T(n)=T(n−1)+T(n−2)+O(1)
因为我们会重复计算很多次 fib(n- ...
5. 分治算法 Divide and Conquer
分治思想
将一个输入变成多个 sub-inputs
将一个 subinput 通过递归找到子解决方法
结合 (combine, or conquer) 子解决方法得到最终解决方法
归并排序
将一个线性数组分割成两个等长的数组,长度 n/2
对左右子数组分别执行归并排序(递归)复杂度
将左右数组进行合并, 复杂度 O(n)O(n)O(n)
递归部分复杂度分析
首先我们明确这是一个类似二叉树的结构,所以,从层数上来讲,一共有 log2n\log_2 nlog2n 层,每一层的复杂度是 O(n)O(n)O(n) (每一层都有合并),所以递归部分的复杂度是 O(nlogn)O(n \log n)O(nlogn)
注意区分一般的二叉遍历
比如对分查找,我们想找到有序数组中最靠近 k 的位置,那么用对分查找,相比归并排序少了一个合并 (O(n)) 的步骤,时间复杂度是 O(logn)O(\log n)O(logn)
又或者是将一个数不断的用 ⌊x/2⌋\lfloor x/2\rfloor⌊x/2⌋ 和 x−⌊x/2⌋x - \lfloor x / 2\rfloorx−⌊x/2⌋ 来 ...
0. 统计学概念
基本概念
population: 一个实验中所有数据的综合
sample: population 的一个子集,包含了一些已经被观察过的元素
outlier: 一个样本中与其他数据相差较大的数据
简单随机样本 SRS
尺寸为 n 是一个每个元素都相同可能性下被挑选出来的sample
常见计算公式
样本均值 sample mean
即样本的平均值
xˉ=∑i=1nxin\bar{x} = \frac{\sum_{i=1}^{n} x_i}{n}
xˉ=n∑i=1nxi
偏差 deviation
一个样本值到平均值的距离
xi−xˉx_i - \bar{x}
xi−xˉ
样本方差 sample variance
样本值到平均值的距离的平方和
s2=∑i=1n(xi−xˉ)2n−1s^2 = \frac{\sum_{i=1}^{n} (x_i - \bar{x})^2}{n-1}
s2=n−1∑i=1n(xi−xˉ)2
为什么是 n - 1?
slides 上说实测效果更好,用 n 作为分母会 underestimate the population variance
...
