位运算实现加减乘除

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;
     }
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值