编程语言的巧妙之处-位运算

如何不使用+,-运算符号计算两个数之和?

在编程语言中除了+,-等符号运算,还有位运算.

^,异或,相同为0,不同为1.

比如 : 2^3

        0 0 1 0
        0 0 1 1
        _______
        
        0 0 0 1          (相同出0,不同出1,结果=1)


      2^3 = 1;

                                    

&,与,同1出1,有0为0.

比如 2&3

            0 0 1 0
            0 0 1 1
            _______

            0 0 1 0       (同1出1,有0出0,结果为2)

    2&3 = 2;

<<,向左位移.

比如 2<<1

    0 0 1 0
    _______

  0 0 1 0 0   (左移1位,低位用0补齐,结果是4)


 2 << 1 = 4;

由于正数的源码,补码,反码都一样,相对简单,来分析一下如果是负数的左移

比如
    -3 << 2

    在计算机中所有数字都以补码存储:
    所以对于数字-3有,
    源码: 10000000 00000000 00000000 00000011;
    反码: 11111111 11111111 11111111 11111100; (符号位不变,其他位按位取反)
    补码: 11111111 11111111 11111111 11111101; (最低位+1,-3在计算机中的实际存储)
    左移2位后的补码:
          11111111 11111111 11111111 11110100; (左移2位,低位用0补齐,最高位为符号位)
    反码: 11111111 11111111 11111111 11110011;(补码-1)
    源码: 10000000 00000000 00000000 00001100; (结果为-12)
 -3 << 2 = -12;

     

>>,向有位移.

比如 2>>1

     0 0 1 0
     _______

     0 0 0 1      (右移一位,结果为 1)


    2 >> 1 = 1;


比如-3 >> 2

    我们已经知道-3的补码为:11111111 11111111 11111111 11111101;
                 右移两位:11111111 11111111 11111111 11111111; (负数符号位不变,右移两位,高位用1补齐)
                     反码:11111111 11111111 11111111 11111110; (补码-1)
                     源码:10000000 00000000 00000000 00000001; (反码取反,结果等于-1)

    -3 >>2 = -1;

>>>无符号右移.

比如 2>>>1

        0 0 1 0
        _______

        0 0 0 1  (无符号左移1位,结果为1)

        2>>>1 = 1;

>>>与>>唯一的不同是它无论原来的最左边是什么数,统统都用0填充。(包括负数)
    
  比如 -3 >>> 5;

  已知-3的补码为:11111111 11111111 11111111 11111101;
   无符号右移5位:00000111 11111111 11111111 11111111; (高位用0补充)
           源码:00000111 11111111 11111111 11111111; (最高位是0表示正数,正数原反补码一致)
           结果为:
           1*2的26次方+ 1*2的25次方 +....+1*2的0次方 = 134217727;

    -3>>>5 = 134217727;

那么基本的位运算现在我们都已经了解了.来看前面提出的问题:

比如  2 + 3 = 5;
      
而我们知道 (2+3也可以使用位运算)
    
    0 0 1 0
 +  0 0 1 1
    _______

    0 1 0 1   (结果等于5)

而 2^3
    0 0 1 0
    0 0 1 1
    _______

    0 0 0 1  (可以表示为2+3逐位相加后除进位外剩下的数字 1+0=1=1^0)
而 2&3
    0 0 1 0
    0 0 1 1
    _______

    0 0 1 0 (可以表示为2+3逐位相加后的进位1+1=0(进位1=1&1),只不过结果应该左移1位,即 2&3<<1)

    0 1 0 0 (左移一位)

然后将异或的结果和左移一位后的与结果相加

    0 1 0 0 
 +  0 0 0 1
___________

    0 1 0 1 (结果等于5,此时的加法重复上面的运算 即 2+3 = 2&3<<1+2^3 = 4&1<<1 + 4^1)

什么时候应该结果重复运算?
    当进位结果等于0时,运算结束,得到结果:

    0 1 0 0
    0 0 0 1
___________

    0 0 0 0 (4&1<<1 = 0 结束,此时4^1 = 5,所以3+2 = 5)

java代码如下

    int sum (int a, int b){
        int sum = a^b;
        int cur = a&b<<1;
        if(cur==0)return sum;
        retturn (sum,cur);
}

最后我们终于完成了3+2=5!!!!!!!!!!!!!!!!!!!!太难了,哈哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值