如何在mc里打造一个计算器[2] -- 加减法器

在第0篇的结尾我说到了一个叫半加器的东西, 它可以处理两个1bit输入的加法, 并且输出一个本位和进位 such: 输入 1, 1 输出 1, 0, 其中输出为1的叫做进位, 输出为0的叫做本位
半加器在mc里有很多种实现方法, 不过主要还是分为两种, 两个输入端在水平方向一致, 和在垂直方向一致, 这里有两个例子 (第二个是借鉴别人的)



一般来说我还是推荐使用垂直方向的, 因为mc的红石特性使得横向占地很大, 而使用水平方向的只会让你的计算器占地更大从而造成大量卡顿 (心累.jpg)

有了半加器之后, 可以开始着手制作简单的加法器了
半加器其中有一个进位, 这说明进位需要留着下一个bit处理 *下一个一般指的是左边的, 但是半加器只有两个输入, 两个本位输入加上上一位进位一共3个输入, 所以我们需要一个新的部件处理3个输入的加法
现在我们假设3个输入都是1, 那么加起来就是3, 也就是二进制的11, 可以看出在极限情况下输出也只有2个, 一个进位一个本位,
那么这种处理三个输入的加法部件就可以做为这样:


AB是两个本位输入, S_bar是上一位的进位, S是进位输出, C是本位输出
这个部件就叫做全加器, 把全加器串起来就是一个通用的加法器了:

那么现在我们就实现了最简单的 A+B 加法操作了

那么减法如何实现呢
A-B可以看作A+(-B), 而-B可以看作0-B, 那么问题来了, 如何进行0-B这个操作?
先来举例子: -1 + 1 = 0, 而在4bits里, 1表示为0001, 那么我们需要寻找一个数字B`, 使得B` + 0001 = 0000, 这明显在二进制是不存在的, 但是如果我们考虑溢出整形的话?
那么上述等式可以变成 B` + 0001 = 10000 → 0000, 那么就可以知道 B` = 1111
也就是说考虑溢出整形的话, 1111与-1的作用是一样的

那么在允许溢出整形的情况下如何求得其他数字的相反数呢?
我们的重点是溢出整形, 并且溢出后需要整形为0000, 那么在溢出前最大的数字就是1111
然后我们的思路可以变为这样, 一个数字C, 它与B相加后为1111, 那么C+1就可以在形式上表示为-B *** C+B=1111, (C+1)+B=1000→0000
简单可知C与B互为补数, 幸好在二进制里取补数最方便的方法就是取反, 即 C = not B
那么就可以得到负数的求得过程: -B = (not B) +1
并且为了区分1111和1111, 一般有一个符号位在最左边, 也就是说在5bit整数里, -1 = 11111, 15=01111,
但是一般不存在5bits这种奇葩的位数, 所以用8bits来做示例的话:
0 = 00000000; -0 = 10000000
1 = 00000001; -1 = 111111111
127 = 01111111; -127 = 10000001
这就是一般说的8位符号整数 8int 的表示方法了, 最大数字: 127, 最小数字:-127

说了那么多废话, 那么加减法器在mc怎么实现呢
我们已经知道是否启用减法要看符号位, 而我们习惯用S表示符号位, M表示数字本体
那么加减法器就可以表示为这种结构

而一块关于减法的东西应该满足下面的条件

经过一番头脑风暴后, 可以化简得到 Out = 此内容已被隐藏, 需要回复以查看内容
这个算式做成部件后就是这部分了

注意: 为了使得 6 + (-4) 这种计算成立, 符号位S也应该参与到加法计算中, 例子:(8bits)
00000110 + 11111100 = 1 00000010 → 00000010
可以看出符号位非常自然地被进位顶走了, 经过整形后得到的结果正是2
这种计算方法会让超过位数限制的计算得出奇怪的结果, 例子: 120 + 56
01111000 + 00111000 = 10110000 得到的结果是176, 明显超出了8int的范围, 但是计算机是不知道这种事情的, 并且会把10110000继续按照8int处理得到 -80
这种情况是真实存在的, 所以这里为了还原这种bug也不做专门的溢出处理了
有兴趣的可以自己去尝试做一下一部分的溢出处理

加减法器就到此结束了, 只要努力自己思考一下就可以慢慢拼凑出来的东西, 所以也不存在存档这种东西了
其实封面就是一个"触发型"的32bits加减法器= =
***** Out = (M xor S) + S