本 Wiki 开启了 HTTPS。但由于同 IP 的 Blog 也开启了 HTTPS,因此本站必须要支持 SNI 的浏览器才能浏览。为了兼容一部分浏览器,本站保留了 HTTP 作为兼容。如果您的浏览器支持 SNI,请尽量通过 HTTPS 访问本站,谢谢!
Week 2 notes
二进制数以 0
,1
的组合表示各式各样的数据:n
位二级制数拥有 2n 的组合数量。
二级制按照如下的规则转化为十进制:
比如下面的例子, 101
转化的的结果是 5
:
也就是如果有 k
位 Bit,最大能表达的数字为:
1+2+4+...+2k−1=2k−1
计算机中字的长度是有限的,因此表示的范围也是有限的。理想情况下,一个 8
位的字可以表示 28=256 个数字;但实际上,如果需要表示负数,那么 8
位的其中一位就会作为符号位,这样 8 bit 只能表示 0-127
按之前转化的逆顺序:
2^n
计算出的数1
(20)
这个过程相当于是在还原二级制构造十进制的过程。因此,之前能找出来的数证明其对应的 Bit 上都是 1
,反之都是 0
。以 87
位例:
如果最后一位相加也需要进位,此时结果长度超出了字的长度。我们称该情况为加法溢出(overflow)。解决的方式是:忽略所有额外的进位。从计算机的角度来考虑,如果加法超出了字长的限制,那么我们做的加法,就不再是真正的加法了。
从这个思路出发,Adder 的设计分为:
Half Adder 完成的工作是将两个 Bits 相加。那么:
x
, y
需要注意的是,两个 Bits 相加只和当前的 Bit 有关。只要是 1 + 1
,那么进位就是 1
,结果就是 0
。因此,我们可以得到如下的真值表:
这个 adder 由一系列的 half adder 和 full adder 组成。准确的来说,是 15 个 full adder 与 1 个(最右边的)half adder 组合在一起,组成了 16 bits 的,带进位的加法计算器。
表示负数的方式有三种:
这种方式使用二进制的最高位作为符号位,以此来区分正负数。其他位不变,比如:
000 -> 0 100 -> -0
001 -> 1 101 -> -1
010 -> 2 110 -> -2
011 -> 3 111 -> -3
-0
的定义,它与 0
的区别无法解释1 + (-1)
,也就是 001 + 101
, 结果是 110
,为 -2
, 不是 0
这种方式下,所有的负数都用 bits 可以表示数字的总数来减去负数对应的整数,即: 2n−x 比如:
// 4 bits, total numbers: 2^4 = 16
3 -> 0011
// decimal
-3 -> 16 - 3 = 13 -> 2^3 + 2^2 + 2^0 -> 1101
使用补码表示负数可以将负数的加法(减法)转化为加法:
根据上面的例子,这个过程分为了三步:
上面计算负数的过程是将二进制转化为十进制来进行的。实际上,利用补码公式的变形,就可以很轻松的用二进制直接计算负数: 2n−x=1+(2n−1)−x 观察一下上面的变形,可以发现:
1 -> 1
2^n - 1 -> 11111....1111
16 - 2
-> 15 - 2 + 1
-> 1111 - 0010 + 1
-> 1101 + 1
-> 1110
Arithmetic Logic Unit (ALU) 在冯诺依曼架构中充当了很重要的角色。具体的来说:
ALU 的设计在硬件和软件中均可实现。硬件实现下,ALU 的速度会更快,但成本会更高。
本课例子(HACK ALU):
Hack ALU 常用的 18 种运算的真值表如下:
上面 6 个控制位均在 0 和 1 时代表了两种不同的运算:
整个计算过程从左到右进行运算,前面的运算结果会作为下一次的算子参与新的运算。比如下面的例子:
// input
x = 0010
y = 1011
// calculation: y - x
// control bits sequence from the turth table
0 0 0 1 1 1
// compute process
zx = 0 // do nothing
x = 0010
y = 1011
zy = 0 // do nothing
x = 0010
y = 1011
zy = 0 // do nothing
x = 0010
y = 1011
ny = 1 // y = !y
x = 0010
y = 0100
f = 1 // out = x + y
x = 0010
y = 0100
out = 0110
no = 1 // out = !out
out = 1001