本 Wiki 开启了 HTTPS。但由于同 IP 的 Blog 也开启了 HTTPS,因此本站必须要支持 SNI 的浏览器才能浏览。为了兼容一部分浏览器,本站保留了 HTTP 作为兼容。如果您的浏览器支持 SNI,请尽量通过 HTTPS 访问本站,谢谢!
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录前一修订版后一修订版 | 前一修订版 | ||
cs:comp_n_arch:courses:fnti_i:week_2 [2025/04/03 14:19] – [2's Complement(补码)] codinghare | cs:comp_n_arch:courses:fnti_i:week_2 [2025/04/05 12:34] (当前版本) – [控制位与 16bits 输出位的真值表] codinghare | ||
---|---|---|---|
行 77: | 行 77: | ||
===2's Complement(补码)=== | ===2's Complement(补码)=== | ||
这种方式下,所有的负数都用 bits 可以表示数字的总数来减去负数对应的整数,即: | 这种方式下,所有的负数都用 bits 可以表示数字的总数来减去负数对应的整数,即: | ||
+ | 2n−x | ||
+ | 比如: | ||
+ | <code CIL> | ||
+ | // 4 bits, total numbers: 2^4 = 16 | ||
+ | 3 -> 0011 | ||
+ | // decimal | ||
+ | -3 -> 16 - 3 = 13 -> 2^3 + 2^2 + 2^0 -> 1101 | ||
+ | </ | ||
+ | 这种情况下,正数的表达范围为 [0,2n−1−1],负数的表达范围为 [−1,−2n−1] | ||
+ | ==补码的优势== | ||
+ | 使用补码表示负数可以将负数的加法(减法)转化为加法: | ||
+ | \\ \\ | ||
+ | {{ : | ||
+ | 根据上面的例子,这个过程分为了三步: | ||
+ | - 求出负数的补码结果(正数,比如 −2=16−2=14) | ||
+ | - 将得到的正数转换为二级制相加 | ||
+ | - 当存在 overflow 时,溢出位将被自动丢弃,比如此处 14+13=27,丢弃溢出位后结果为 27−16=11 | ||
+ | - 11 是以补码形式,根据公式,负数的表现形式为:24−positiveNumber=11。可以得到正数的值为 5,因此 11 对应的负数为 −5 | ||
+ | ===计算 -x=== | ||
+ | 上面计算负数的过程是将二进制转化为十进制来进行的。实际上,利用补码公式的变形,就可以很轻松的用二进制直接计算负数: | ||
+ | $$ | ||
+ | 2^n-x = 1 +(2^n-1) -x | ||
+ | $$ | ||
+ | 观察一下上面的变形,可以发现: | ||
+ | <code CIL> | ||
+ | 1 -> 1 | ||
+ | 2^n - 1 -> 11111....1111 | ||
+ | </ | ||
+ | 那么也就是说,−x 的实际结果,等于所有 bits 都是 1 的数减去 x 对应的二进制,再加上一。比如 −2,如果以 4 bits 的 | ||
+ | 二进制表示,就是: | ||
+ | <code CIL> | ||
+ | 16 - 2 | ||
+ | -> 15 - 2 + 1 | ||
+ | -> 1111 - 0010 + 1 | ||
+ | -> 1101 + 1 | ||
+ | -> 1110 | ||
+ | </ | ||
+ | 从形式上来看,x 的负数结果实际上是直接将 x 的二进制**按位翻转**后再**加上一**得到的。 | ||
+ | ====Arithmetic Logic Unit==== | ||
+ | // | ||
+ | * ALU 扮演的是函数的角色,也就是接受输入,然后按指定的方法计算结果的的计算单元。 | ||
+ | * ALU 对应的函数是**提前定义**的,**算术**或**逻辑**运算的一种(或是这两者的组合) | ||
+ | <WRAP center round box 100%> | ||
+ | ALU 的设计在硬件和软件中均可实现。硬件实现下,ALU 的速度会更快,但成本会更高。 | ||
+ | </ | ||
+ | ===实例:Hack ALU=== | ||
+ | 本课例子(HACK ALU): | ||
+ | * 接收两个 16 bits 的输入 | ||
+ | * 得到一个 16 bits 的输出和两个 1 bits 的输出。 | ||
+ | * 实现了一系列的(总共18个)**基础**函数 | ||
+ | * 调用哪个函数通过结构图正上方的 6 个 1 bit 的输入来决定。 | ||
+ | 其结构图如下: | ||
+ | \\ \\ | ||
+ | {{ : | ||
+ | \\ | ||
+ | ==控制位与 16bits 输出位的真值表== | ||
+ | Hack ALU 常用的 18 种运算的真值表如下: | ||
+ | \\ \\ | ||
+ | {{ : | ||
+ | \\ | ||
+ | 上面 6 个控制位均在 0 和 1 时代表了两种不同的运算: | ||
+ | \\ \\ | ||
+ | {{ : | ||
+ | \\ \\ | ||
+ | 整个计算过程从左到右进行运算,前面的运算结果会作为下一次的算子参与新的运算。比如下面的例子: | ||
- | $$\textttt{2^n | + | <code CIL> |
+ | // input | ||
+ | x = 0010 | ||
+ | y = 1011 | ||
+ | |||
+ | // calculation: | ||
+ | // 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 | ||
+ | </ |