面试题:仅使用位运算将数字扩大k倍

前提

    不知道有什么巧妙解法,这里说一个通解,那就是用位运算实现加减乘除。

为什么要用位运算实现加减乘除?

    了解计算机通过半导体实现加减乘除的逻辑 不装了,其实根本就是面试可能会问 加法这里可能会啰嗦一些,后面基于加法就没有这么痛苦了

加法

    加法,其实是由两种状态组成的: 第一是各个数位都没有进位,这种最简单,就是将对应位置的数值直接相加即可 第二是则是数位中有进位,这种也不难,首先是将对应位置数值加起来之后,要模上进制数,然后考虑进位数怎么计算,回忆下加法的过程,进位数其实就是当前数字除以进制数的下整数,然后再将其加到前面一个数位中,迭代执行,直到没有进位。 这就引发了一个问题,既然进位数需要通过除法得到,但是除法又不允许使用,这是否陷入了困境? 幸运的是,二进制数的进位其实更简单,因为进位数非0即1,因此,我们只需要知道如何得到正确的进位数即可。 我们发现,二进制中,如果有相加数的对应位不都是1,那么就没有进位,此时进位是0,如果有进位,那么对应位置往前进1位,用二进制实现该逻辑就是(a&b)<<1 进位问题解决了,那么其他部分呢,其他部分就如刚刚所说,数位数字模上进制数即可,对于二进制的模2加法,就是异或,也就是a^b
int add(int a,int b) {
          
   
  int carry,add;
  do{
          
   
    add = a^b;
    carry = (a&b)<<1;
    a = add;
    b=carry;
  }while(carry!=0);
  return add;
}

减法,重捡大一知识

    因为a+b = a+(-b),我们只需要明白二进制如何取相反数即可 千万要注意,虽然一般数据类型的第一位都是符号位,但是并不是说0000…0001的相反数就是1000…0001,而是严格遵循相反数的定义,a+(-a)=0 二进制中的取反操作比较巧妙,是将数位取反之后+1,也就是-a = ~a+1,这里就不做展开,清楚取反之后,减法就非常简单了,因为我们已经实现了加法
int substract(int a, int b){
          
   
	return add(a, ~b+1);
}

乘法,n次加法

    直观来看,乘法就是n次加法迭代,o(n)
int multiply(int a,int b){
          
   
  int ans = 0;
  while(b--){
          
     
      ans = add(ans, a);
    }    
  return ans;
}
    优化,二分加法,因为左移操作相当于乘2, 因此我们配合左移操作与add操作,即可减少大量运算,该思想就是快速幂的思想,在这里我们就叫它快速乘吧,复杂度降低到o(log n)
int multiply(int a,int b){
          
   
  int ans = 0;
  while(b){
          
   
     if(b&1) add(ans, a);
     a<<1;
     b>>1;
  }
  return ans;
}

除法

    与乘法类似,除法对应的就是n次减法 直观解(只考虑整数除法):
int divide(int a, int b){
          
   
	int ans = 0;
	while(a>=b){
          
   
        ans = add(ans,1);
        a = substract(a,b);
    }
    return ans;
}
    优化,与乘法相反的过程,每次从1寻找距离最大倍数的一半倍数, 减去该数字之后,再比较剩余数字。
int div(int a,int b){
          
    

    int ans=0;
    while(a >=b){
          
   
        int multi=1;
        while(multiply(multi, b) <= (a>>1))
        {
          
   
            multi=multi<<1;
        }
        ans= add(result, multi);
        a = substract(a, multipy(b, multi) );
    }
    return ans;
}

总结

    感觉自己在写汇编代码 不得不佩服计算机研究者们的智慧

参考

经验分享 程序员 微信小程序 职场和发展