1. 加法
例:13 的二进制位 1101 ; 9 的二进制为 1001
分析
步骤一
不考虑进位 sum = 1101 + 1001 = 0100
步骤二
只考虑进位 carry = 1101 + 1001 = 10010
步骤三
carry = 0 ? 不为0 ,重复步骤一,二,三;为0结束,结果为sum
本例中
1. 不考虑进位 sum = 1101 + 1001 = 0100
2. 只考虑进位 carry = 1101 + 1001 = 10010
3. carry 不为 0
4. 不考虑进位 sum = sum + carry = 0100+10010 = 10110
5. 考虑进位 carry = 0
6. 结束 结果为 sum = 10110 = 22 = 13 + 9
分析:
第一步中不考虑进位的加法就是 异或运算
第二步中考虑进位的加法就是 与运算结果向左移动一位
第三步就是重复第一步和第二步,直到第二步进位的结果为0
算法实现
// 非递归形式实现
int add(int a,int b){
int carry;
while(b != 0){
carry = (a&b)<<1;
a = a ^ b
b = carry;
}
return a;
}
// 递归形式实现
int add(int a,int b){
if(b == 0){
return a;
}else{
int carry = (a & b)<<1;
a = a ^ b;
return add(a,carry);
}
}
2. 减法
加法操作只有,加,进位两个操作,而减法还会有借位,进位我们知道可以通过与运算并左移一位得到,但是借位就不好操作了。
所以减法运算我们也通过加法运算来实现,比如 10 - 6,可以是 10 +(-6);
那么数字的正负号变号呢?
先说一下二进制在内存的存储:
二进制数在内存中以补码的形式存储
另外,正数的原码、补码和反码都相同
负数的反码与原码符号位相同,数值为取反;补码是在反码的基础上加1
比如:
~9的计算步骤:
转二进制:0 1001
计算补码:0 1001
按位取反:1 0110
转为原码:1 0110 (此时为负数,但是要以补码的形式展示出来)
按位取反:1 1001 反码
末位加一:1 1010 补码
符号位为1是负数,即-10
规律:~x=-(x+1);
因此,t=~9(1001)并不能输出6(0110),而是-10;
数字的正负号变号的方式,求取步骤:
第一步,每一个二进制位都按位取反,得到补码。
第二步,将上一步得到的值加1。
算法实现
int subtraction(int a,int b){
int b = ~b + 1;
retrun add(a,b);
}
3. 乘法
从上图的计算过程可以看出,如果乘数当前位为1,则取被乘数左移一位的结果加到最终结果中;如果当前位为0,则取0加到乘积中(加0也就是什么也不做);
算法步骤分析
第一步:判断乘数是否为 0 ,如果为 0 ,直接执行最后一步;
第二步:判断乘数的末尾是否为 1 (将乘数与 1 做 与运算),如果为 1 ,则相加数为当前被乘数,如果为 0 ,则相加数为 0 ,将相加数加到最终的结果中;
第三步:被乘数左移一位,乘数右移一位,返回第一步;
第四步:确定符号位,输出结果。
代码实现:
int multiply(int a,int b){
//将乘数和被乘数都去绝对值
int multiplicand = a < 0 ? add (~a,1) : a;
int multiplier = b < 0 ? add (~b,1) : b;
//计算乘积
int product = 0;
while(multiplier > 0){
if((multiplier & 1)== 1){//判断最后一位是否为1
product = add(product,multiplicand);
}
multiplicand = multiplicand << 1; //乘数左移
multiplier = multiplier >> 1; //被乘数右移
}
// 计算乘积结果的符号;
if((a^b) < 0){
product = add (~product,1);
}
return product;
}
4. 除法
除法运算很容易想到可以转换成减法运算,即不停的用除数去减被除数,直到被除数小于除数时,此时所减的次数就是我们需要的商,而此时的被除数就是余数。
这里需要注意的是符号的确定,商的符号和乘法运算中乘积的符号确定一样,即取决于除数和被除数,同号为证,异号为负;余数的符号和被除数一样。
分析
计算机是一个二元的世界,
所有的int型数据都可以用[2^0, 21,…,231]这样一组基来表示(int型最高31位)。
不难想到用除数的231,230,…,22,21,2^0倍尝试去减被除数,
如果减得动,则把相应的倍数加到商中;
如果减不动,则依次尝试更小的倍数。
这样就可以快速逼近最终的结果。
2的i次方其实就相当于左移i位,
为什么从31位开始呢?
因为int型数据最大值就是2^31。
代码实现
int division(int a,int b){
int res;
if(a<b){
return 0;
}else{
res=division(subtraction(a, b), b)+1;
}
return res;
}