正文之前
今天是开始念书的第一天,果然没压力了就是不一样的啊!!十二点半睡觉,然后如果是考研期间,八点是最晚起来的, 但是今天八点多醒来一次,然后倒头继续睡,醒来一看 "十点半" ,心痛!我是个没有上午的男人!!!
正文
1、 加法
计算机执行的都是二进制的加法,也存在进位这个概念。那么对于ALU(算术逻辑单元)来说,当两个相加的数符号相同的时候,会存在最高位溢出的风险,所以最好是用第33位来表示最后是否进位(溢出),但是两个符号相异的数相加,就不存在这个问题,直接用32位寄存器表示结果即可:
1101
+ 11
----------
10000
2、 减法
减法其实就是把赋值表示为补码形式,然后与另一个数直接相加即可,转换后规则同加法
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
3、乘法
直接实例表示吧,慢慢讲原理实在是难懂而且还麻烦
被乘数:
1101(13)X 0101(5) = 01000001(65)
1101 被乘数
X 0101 乘数
----------
1101
0000
1101
0000
-------------------
01000001(65) 乘积
//上述就是二进制的乘法的运算过程,那么在加法器算术逻辑单元(ALU)中是如何实现呢?
那么根据上述人类的算法,我们可以这样思考,首先腾出一个乘积的寄存器,初始化为0 ,然后执行下列的程序:
乘数右移想必大家都懂,但是为什么被乘数要左移呢?因为乘数右移之后,但是它所代表的数量级是不变的,这一位代表的是2^n
次方,而不是代表个位,那么对应的,既然无法在乘数上体现出来,当然就只能改变被乘数了。得益于X2
可以改为左移这一二进制优化方案,每次对乘数的更高位操作,不需要改变其他的,只要对被乘数X2
即可,自然地,被乘数的左移其意义也就出来了, 就好像上面的例题中,第三步是要对原本的乘积加上四个1101(4*13=52)
那么我们只需要对被乘数左移两次,自然就得到了四个1101
也就是110100(也就是52)
。跳出的条件是一般都是要执行完32次之后。
4、 除法
除法是最麻烦的,这一点毫无疑问。
被除数 = 商 X 除数 + 余数
1001 (商)
(除数)- - - - - -
1000 | 1001010 (被除数)
1000
-- --
10
101
1010
1000
- -- -
10 (余数)
上面是76/8=9 ··· 4
的二进制除法表达式,可以看到,我们是对余数寄存器初始化为被除数,然后每次减一次除数具体的过程见下面的流程图:
除法的计算方法跟乘法有一定的共同之处,但是又很大程度上的不同,主要的区别的是引入了余数这个概念。并且并且巧妙地把除数放在64位寄存器的高32位,这样的话就可以避免一开始无法直接计算出要右移多少位才能正确的相减(这其实也是一种偷懒吧,毕竟前面起码有除数 位数次的空白计算循环)
5、 有符号的乘除
这个是很麻烦的一个处理项,虽然对于人类来说这个是一眼就能看出来的,但是计算机不一样。所以我们需要有别的机制保证有符号的计算的正确性。对于乘法,记住符号位,并且判定结果是正是负,然后最后的一次的时候加上即可,只有最高31位的乘法。除法则不一样。因为我们必须设置余数的符号,余数不能为负数,不然就会出现
(-7)/2 = -3 ···(-1) 还是 (-7)/2 = -4 ···(-1)
这两种看似都正确但是结果完全不同的情况。所以要保持被除数与余数的符号相同。那么我们可以得到下面的结论:
正确的有符号除法算法在源操作数的符号相反时商为负,同时要使得非零余数的符号与被除数的相同! 注意是被除数而不是除数和商!!
正文之后
有点时间我也会怀疑,每天这么写,至少一天要花一个小时到两个小时去排版,到底值得不?虽然目前还没看出多少效果来,粉丝数这事我也看得越来越淡,但是其实还是有好处,毕竟每天重温一次,并且相当于做读书笔记,感受书籍作者的思路,相当于自己重新编写一本书,还是不错的吼~~ 本篇笔记到此为止,昨晚整了下关于shell编程,估计今天晚上会出一篇 Linux Shell入门的文,希望喜欢!!