聊聊使用位运算来实现加法(老物)

好久没写资料了,一方面是现在要写的东西太多,思考的事情也太多,都没什么时间来坐下来整理一下有趣的资料出来(其实还是因为自己太懒。)

今晚偶然间看到有人问起了不用内置 + 运算符怎么实现 + 法,这个问题让我想起了不用比较运算符( < 、 > 、 = )怎么实现比较,其实都不是问题,用我的理解方式去理解其实就是一个小学的问题 = -= 。

那按我前面所说的就设置一个最终目标吧。

如何从零开始实现一个比较运算符。

(显然今天这篇是讲不到最终目标了,也许以后也讲不到了,不过看完这篇文章后,你应该就知道怎么做了。)

首先我们先在数学上讲得通道理,再拿到计算机里面看着实现,比较这事情呢,主要就看与 0 的结果。
比如:a > b => a - b > 0,那我们只需要知道 (a - b) 的结果的正负号就可以做出比较的结果了。
所以我们得有正负数的定义吧,然后还得有(a - b)的减法实现吧。
那么如何实现减法呢?一个正数加上一个负数是不是就有了减法呢?确实是。
所以今天的主题就回到标题上,只要有了加法,那就会有了减法,同样也会有乘法,甚至就会有了比较运算,就如上解释可知。

小时候,我们最早计算 9 + 11 的时候是这样算的。

      11
    +  9
    -------
      20

没错吧,这个我认为中国人都应该知道的吧,自行百度 竖式计算 。
其实,这个在二进制数中也是可行的,而上面那个是十进制的,二进制的就叫逢二进一。

      11    =>        1011
    +  9    =>    +   1001
    -------        --------
      20             10100

这个结果你能接受的话,那我们就进入到代码实现部分吧。

对于二进制的竖式计算中存在两个逻辑,分别是 进位 和 合并 。
进位指对列同为 1 的执行逢二进一,合并指对列不同数值的执行为 1 。
以上逻辑将分别用二进制运算来取代,前者可以视为按位与(&)和左移一位,后者可以视为两数执行按位或。
我附加一点二进制运算说明吧。

在位运算中 ^ 和 & 分别产生以下结果。

      1011
    ^ 1001
    ---------     
      0010

数学意义为,模拟逢二进一的相加结果,保留未进位的结果,这是为了模拟竖式计算的加法结果。
(因为同为 1 则进位,同为 0 无结果,最终结果都是要将其变为 0 ,则可以理解为进位后的结果。)

      1011
    & 1001
    ---------     
      1001

数学意义为,标记所有进位位置,对其执行 << 1 即可得到进位的结果。

以 1011 + 1001 为例:

根据竖式运算可知:

      1011  // 
    + 1001  // 
    ---------
     00010  // 先 1011 ^ 1001 合并得到未进位的结果( 1011 ^ 1001 = 00010 )
     10010  // 1011 & 1001 = 1001 不为 0 存在进位,故执行 1001 << 1 得到进位后的结果 1001 
    ---------
     10000  // 通过 00010 ^ 10010 合并得到未进位的结果( 00010 ^ 10010 = 10000 )
     00100  // 00010 & 10010 = 00010 不为 0 存在进位,故执行 00010 << 1 得到进位后的结果 00100 
    ---------
     10100  // 通过 10000 ^ 00100 合并得到未进位的结果( 10000 ^ 00100 = 10100 )
     00000  // 10000 & 00100 = 00000 ,此时结束运算。
    ---------

合并(^)结果后检查是否为可进位(&),直到最终不存在可进位的数,则说明加法结束。

最后贴个代码。

uint add(uint a, uint b)
{
    uint sum, carry;
    while(1)
    {
        sum = a ^ b, carry = a & b;
        if(0 == carry) 
    {
        break;
    }
        a = sum, b = carry << 1;
    }
    return sum;
}

uint Add(uint a, uint b)
{
    uint sum = a ^ b, carry = a & b;
    return (0 != carry) ? Add(sum, carry << 1) : sum;
}

转载于:https://www.cnblogs.com/juwan/p/11448980.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值