汇编基础之一 -- 位运算和四则运算的实现
位运算
计算机只能操作0和1,因此无论是储存数据或者的进行计算都只能通过二进制的方式储存或则处理。并且只能有以下的位计算方式(因为这些位运算方式都能通过实际的物理电路图实现),其余的计算例如加减乘除四则运算都是在下面几种基本运算方式中延展出来的。
1、&:位逻辑与。1&1为1,其余为0
2、 |:位逻辑或。1|1或1|0为1,0|0为0
3、^:位逻辑异或:相异出1,即,1^0活0^1为1,1^1或者0^0为0。
4、~:位逻辑反:~1为0,~0为1。
5、>>:右移。汇编中有两种右移。shr右移,高位补0,sar右移,高位补符号位的数,也就是移位前最高位的数。汇编中数据没有类型,在高级语言中才会声名数据类型。在将高级语言中使用>>对一个数进行右移操作,编译器会根据声名数据类型,转变为不同的汇编代码指令。例如
int i=100; i >> 2 有符号数在执行 >> 操作时,会使用SAR指令执行右移,即最高位补符号位 unsignint i=100 i >> 2 无符号数在执行 >> 操作时,会使用SHR指令执行右移,即最高位补0
6、<<:左移
加法
加法计算是实现其他四则计算的基本。所以首先看加法计算。科学家们发现,两个二进制数相加,在不考虑进位的情况下。两个数相加的结果和两个数异或的结果相同。
# 例如 4 + 5 0000 0100 0000 0100 0000 0100 ^ 0000 0101 + 0000 0101 + 0000 0101 (相加但是不进位) ------------- ------------- ------------- 0000 0001 0000 1001 0000 0001
如果两个数相加的过程中,没有发生进位,那么结果可以由异或进行代替,有了上面的方法。剩下的只需要解决进位的问题,我们发现,只有两个值同时为1进行相加的时候,才会进位,并向前进位1,我们通过与运算,就可以将该进位位置找出,然后将该进位向左进一位,即左移一位即可得到进位后的值,将异或结果(没有算进位的值) + 需要进位的值,就计算出了两个数的和。
# 先计算 4 ^ 5 的结果, 先不进位计算,在加上应该进位的值 第一次相加 0000 0100 (4) ^ 0000 0101 (5) ------------- 0000 0001 没有进位的结果 # 找出进位的值,先与, 在左移一位 0000 0100 (4) & 0000 0101 (5) ------------- 0000 0100 << 1 ------------- 0000 1000 应该进位的值 # 将0000 0001 和 0000 1000 两个结果相加即可,但是相加任然需要使用上面的方式异或的方式 第二次相加 0000 0001 ^ 0000 1000 -------------- 0000 1001 没有进位的结果 0000 0001 & 0000 1000 -------------- 0000 0000 没有进位,所以最后的结果为异或的结果,得到结果为 0000 1001 (9)
如果在第二次计算中, 仍然存在进位,只需要继续重复上面的加法计算即可,直到不存在进位,a + b 的结果就为 a ^ b的结果。
原码,反码,补码
首先应该记住一句话,计算机储存的值永远是一个数的补码。
对于正数,我们将5转化为二进制的形式 0000 0101值,这个值我们称为原码,而正数的原码,反码,补码是相同的。所以同样为0000 0101。所以计算机储存0000 0101
-
数据储存在计算机中只是一串0和1,我们怎么知道到它是一个负数还是一个正数。所以科学家们约定了一个符号位,如果最高位的值为1,表示负数。如果为0。那我们人为的用1000 0100来表示-4(注意,人为的表示,并不是计算机中储存的值),这个值为源码,他的反码(符号位不变,其余0,1反转)为1111 1011, 补码(反码 + 1)为1111 1100,而这个补码值才是计算机中储存的真实值。也就是说,计算机中的-4储存的二进制形式为1111 1011。至于源码和反码,只是为了让我们去计算出负数的补码而存在。
乘法
乘法可以看作是多个加法计算,例如 5 * 4,可以作为 5 + 5 + 5 + 5计算,只需要一个循环计算即可。
除法
对于能够除尽的除法,实际上就是减法,例如36/9,即36可以减去多少次9。所以可以在基于36 - 9的基础上,计算减去的次数即可。除法可能出现小数的情况,这涉及到浮点数的计算和储存,情况较为复杂,不做过多讨论。