递归算法(三)——不借助四则运算实现加法
问题
求两个整型变量的和,不能使用四则运算,但可以使用位运算。
思路
以二进制形式,考虑两个整数相加:
a = 01101001b
b = 11100111b
s = ????????
一个常见的结论是:
我们在进行二进制加法的时候(类比十进制加法),若无进位,则直接写上结果;若有进位,则写一个进位标志,作为累计,在高位计算时加入。
也就是说,结果是由截断二进制位和及其进位标志相加而得的。
思考:两个数的和 == 截断二进制位和+进位和,这种转化分解是否可行?
证明:讨论两个1bit相加出现的全部情况,一共有四种。
- 0 + 0 = 0 + 00
- 0 + 1 = 1 + 00
- 1 + 0 = 1 + 00
- 1 + 1 = 0 + 10
等式左边为一位相加,右边为截断结果s和进位c相加,可以看出,等式成立,因此这种转化方式可行。
将等式记为:
a + b = s + c
我们来寻求a、b和s、c的关系。
很容易证明:
- s=a^b,^表示异或,即a、b不同时返回0,相同时返回1。
- c=(a&b)<<1,&表示与,即a、b都为1时返回1,否则返回0;<<表示二进制左移,<<1即乘以2。
这样,转化关系式就得出了:
a + b = a ^ b + (a & b) << 1
但是,在转化关系求出后,还存在一个问题:既然存在转化关系,就有递归调用(迭代),那递归的出口是什么?
如果可以求出递归出口,那么这个方法就完美了。
这相当于问:
a 和 b 有没有终止条件(或者说极限)?
我们假设a和b都是n位二进制数(补码表示,这样a和b的正负性不影响结果),令c=a+b。
初始时,用二进制表示,a = a[n-1] a[n-2] … a[1] a[0],b = b[n-1] b[n-2] … b[1] b[0],c = c[n-1] c[n-2] … c[1] c[0]。
第一次迭代。a=a^b;b=(a&b)<<1。b必为偶数,这样b[0]就是0,又由于a+b=c,故a[0]=c[0]-b[0]=c[0]。
结果为:
a = a[n-1] a[n-2] … a[2] a[1] c[0],
b = b[n-1] b[n-2] … b[2] b[1] 0。
第二次迭代。对于a和b最后一位,运算后结果保持不变,所以问题就归结为a[n-1]~a[1]和b[n-1]~b[1]间的迭代。
结果为:
a = a[n-1] a[n-2] … a[2] c[1] c[0],
b = b[n-1] b[n-2] … b[2] 0 0。
……
第n次迭代。递推可得:
a = c[n-1] c[n-2] … c[1] c[0],
b = 0 0 … 0 0。
所以,a=c,b=0,这就是收敛条件,即递归出口。证毕。
我们还可以得出其他结论:
- 迭代次数的上界是n,超过n,立即收敛。
- 假如b的二进制表示的前缀0有许多,那么收敛速度将大大增加。
- 在迭代过程中,a呈指数增加,b呈指数减少,比率近似于2。
- 假如a和b当中有负数,结果也是正确的,因为位运算是纯二进制运算(补码表示)。
实现
function sum(a,b)
{
return b?sum(a^b,(a&b)<<1):a;
}
递归算法(三)——不借助四则运算实现加法的更多相关文章
- 剑指Offer(书):不用四则运算做加法
题目:写一个函数,求两个整数之和,不得使用四则运算位运算. package com.gjjun.jzoffer; /** * 写一个函数,求两个整数之和,不得使用四则运算 * * @author gj ...
- Opengl_入门学习分享和记录_03_渲染管线(三)借助顶点数组对象VAO提高绑定属性效率
目前我们已经知道了,如果想要顶点着色器解释理解我们的输入数据,就必须要按照以下繁琐的步骤:第一步:将输入的数据复制一份到缓冲区,供OpenGL使用.而这块新出现的区域由VBO管理和表示.(若有多个输入 ...
- 大数四则运算之加法运算--------C语言版(未考虑负数)
/* 声明两个字符数组,用于存储大数,声明两个整数型数组便于计算,将字符数组中的元素转换为对应整数存于整数数组中,将低位放在整数数组低位,便于对齐计算 判断是否有进位,计算结果高位先输出,从数组后往前 ...
- JavaScript中交换两个变量的值得三种做法(代码实现)
javascript在编程时经常会涉及到如何交换两个变量的值,例如常见的冒泡排序,快速排序等:下面我讲根据自己近期所学总结几种常见的交换两个变量值的方法: 方法一:借助第三方变量交换两个变量的值 va ...
- [剑指Offer]65-不用加减乘除做加法
题目 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 题解 用位运算模拟加法的三步: 无进位加法:异或运算. 进位:与运算再左移一位. 直到进位为0结束. 代码 pub ...
- Sql三种分页方法
--分页三种方法--第一种 ROW_NUMBER() OVER( ORDER BY OrgID) AS indexs 大于pagesize*pageindex,少于等于pagesize*(pagein ...
- spring学习总结——装配Bean学习三(xml装配bean)
通过XML装配bean Spring现在有了强大的自动化配置和基于Java的配置,XML不应该再是你的第一选择了.不过,鉴于已经存在那么多基于XML的Spring配置,所以理解如何在Spring中使用 ...
- Java实现小学四则运算练习系统(UI)
github项目地址 :https://github.com/feser-xuan/Arithmetic_test3_UI 小伙伴的博客链接:http://www.cnblogs.com/fukang ...
- github下载源码的三种方式
从github上下载源码的三种方式 CreationTime--2018年6月7日15点21分 Author:Marydon 1.情景展示 2.实现方式 方式一:直接点击"Downloa ...
随机推荐
- RDIFramework.NET V2.5(.NET快速信息化系统开发框架) Web版界面样例(可参考)
RDIFramework.NET V2.5(.NET快速信息化系统开发框架) Web版介绍 现已升级到V2.8,点击查看 B/S结构(Browser/Server,浏览器/服务器模式),是WEB兴起 ...
- JS按回车键实现登录的方法
本文实例讲述了JS按回车键实现登录的方法,该功能有着非常广泛的实用价值.分享给大家供大家参考之用.具体方法如下: 方法一: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 < ...
- Myeclipse8.5 最新注册码以使用方法(可以用到2015年!!!)
已破解的一组,复制即可!(注册码到2015年哦!) name:LIKEcode:YLR8ZC-855550-6067725176540043 使用方法:把注册码贴到Window-->prefer ...
- wex5 教程 之 图文讲解 bind-css和bind-sytle的异同
wex5作为网页开发利器,在前台UI数据交互设计中大量使用了绑定技术,即官方视频教学中也提到了KO,实质是数据绑定与追踪.在前台组件的属性中,为我们提供了两个重要的样式绑定属性,bind-css和bi ...
- Hadoop之为何不使用RAID?
一.引言: 在一次和同事的讨论中遇到一个这样的问题:有一个hadoop集群,在hbase的put数据出现瓶颈,他们想要把datanode上的磁盘做成RAID 0(比如10块磁盘做成一个RAID 0), ...
- HDU 4280:Island Transport(ISAP模板题)
http://acm.hdu.edu.cn/showproblem.php?pid=4280 题意:在最西边的点走到最东边的点最大容量. 思路:ISAP模板题,Dinic过不了. #include & ...
- windows+caffe(二)——图片转换为levedb格式
借鉴于langb2014的 http://blog.csdn.net/langb2014/article/details/50458520 与liukailun09的 http://blog.cs ...
- solr初学
1.我按照网上说的,先去下载了一个版本的额solr.solr-5.4.1 首先有些让我先配饰tomcat,我之前没有接触过solr所以先没去看如何配置,估计也和jdk的配置差不多. 2.下载好后我也想 ...
- Smallest Bounding Rectangle - uva10173
Smallest Bounding Rectangle Given the Cartesian coordinates of n(>0)2-dimensional points, write a ...
- 2016年12月17日 星期六 --出埃及记 Exodus 21:12
2016年12月17日 星期六 --出埃及记 Exodus 21:12 "Anyone who strikes a man and kills him shall surely be put ...