Java如何只使用位运算实现加减乘除

分享一波:程序员赚外快-必看的巅峰干货

前言

接前面一篇博客,这又是某个公司的奇葩面试题(都说了到底是哪家公司才会出这种没营养的面试题)。不过吐槽归吐槽,这个题目还是有点学问的,比前面那个 不使用比较运算符如何比较两个数的大小 强多了(但是还是能看出面试官是在存心刁难人)。

原题是“只给加法,如何实现减乘除”,我寻思着,既然减乘除都不给了,那就加大点难度,加法也别给了吧,今天就手动去实现加减乘除。这里只实现int类型的加减乘除。

一说到这种“不给xxx如何实现xxx的问题”,那第一个想到的就是位运算,因此本篇博客的各种运算也是基于位运算的。关于位运算的知识点,请阅读本博客的看官们自行百度学习。。。。
加法

我们先举个加法的例子:8+9=17,可以转换成10+7,即:二者相加不考虑进位的值,和二者相加只考虑进位的值相加。我们再通过二进制来直观的看一下。

0000 1000 (8)
0000 1001 (9)
0001 0001 (17)

[点击并拖拽以移动]

下面描述一下思路(可能有点绕)。

首先我们看,直接二进制相加的结果,0+0=0,1+0=1,1+1=10。好像能看出点什么。前两个的运算规则复合“异或运算”,而后者则复合与运算并左移1位。

到现在思路就清楚了:a^b的结果是不考虑进位的结果,而a&b<<1是只考虑进位的结果。把二者相加即可。如果相加后,可能还存在进位,那就让这两个数字继续相加,一直到进位为0为止。这里使用递归去实现,感兴趣的可以用循环实现,性能比递归要高。

public int add(int a, int b) {// 得到原位和int xor = a ^ b;// 得到进位和int forWoad = (a & b) << 1;return forWoad == 0 ? xor : add(xor, forWoad);
}

到这里,加法就实现完毕了
负数

计算机中的负数实现,是将正数按位取反获取反码,之后+1获得补码,这个结果就是某个正数所对应的负数。(这个在计算机组成原理、操作系统、计算机导论、离散数学等课本中都有,不记得的请翻一下大学课本。)。

负数的实现其实还是比较简单的,按位取反之后+1即可。

public int negative(int num) {return add(~num, 1);
}

减法

实现了负数之后,我们第一步实现的加法就可以和负数进行运算了,而减法也就变得简单起来。

减法的实现如4-2等价于4+(-2),我们直接使用加法和负数就可以实现。

public int minus(int a, int b) {return add(a, negative(b));
}

绝对值

接下来要实现乘法和除法。乘法和除法可能会有正数和负数相互计算的情况,因此我们实现乘除之前,需要先实现绝对值计算的功能,将运算数字转换成绝对值进行乘除,之后判断是否需要加上负号即可。

public int abs(int num) {if (num < 0) {num = minus(0, num);}return num;
}

乘法

乘法的实现,如11*10,乘法的流程如下面所示。

0000 1011 (11)
0000 1010 (10)

0001 0110 (1011<<1,相当于乘以0010)
0101 1000 (1011<<3,相当于乘以1000)

可以看到,二进制乘法的原理是:从乘数的低位到高位,遇到1并且这个1在乘数的右边起第i(i从0开始)位,那么就把被乘数左移i位得到temp_i,直到乘数中的1遍历完毕后,把根据各位1而得到的被乘数的左移值全部相加即得到乘法结果。

而至于存在负数的运算,可以先获取负数的个数,再将两个数字转换成绝对值计算,最后判断当负数是1个时,计算结果就是负数,其他情况则是正数。

public int multi(int a, int b) {// 先获取负数的个数int negativeCount = negativeCount(a, b);// 负数转正数进行计算a = abs(a);b = abs(b);int i = 0;int res = 0;// 乘数为0则结束while (b != 0) {// 处理乘数当前位if ((b & 1) == 1) {res = add(res, a << i);}b = b >> 1;i = add(i, 1);}if (negativeCount == 1) {// 转为负数res = negative(res);}return res;
}

negativeCount方法

public int negativeCount(int a, int b) {int count = 0;if (a < 0) {count = add(count, 1);}if (b < 0) {count = add(count, 1);}return count;
}

乘法事实上有个简单的实现。乘法就是个连加的过程,如5*4就是4个5相加,这个虽然性能比较低,但是操作起来简单,感兴趣的朋友可以自己去实现。
除法

除法没有什么简单的二进制实现方案,实际计算机中的除法也是通过连减去计算的。a/b的意义就是求a可以由多少个b组成,因此除法可以求a能减去多少个b。至于负数的情况,和乘法相同,不再介绍。

public int sub(int a, int b) {// 先获取负数的个数int negativeCount = negativeCount(a, b);// 负数转正数进行计算a = abs(a);b = abs(b);int res;if (a < b) {return 0;} else {res = add(sub(minus(a, b), b), 1);}if (negativeCount == 1) {// 转为负数res = negative(res);}return res;
}

取模

取模运算的思路和除法一样,也是个连减的过程,一直减到我们减不了为止,剩下的值就是我们要的结果。

public int mode(int a, int b) {// 先获取负数的个数int negativeCount = negativeCount(a, b);// 负数转正数进行计算a = abs(a);b = abs(b);int res;if (a < b) {res = a;} else {res = sub(minus(a, b), b);}if (negativeCount == 1) {// 转为负数res = negative(res);}return res;
}

结语

总的来说,加减乘除的实现还是比较简单的,只是对于初学者来说比较难想。熟悉了这类“不给xxx如何实现xxx”的题目之后,就能第一时间想到位运算了,通过位运算去实现运算符规则,实现起来就没有什么难度了。

最后还是需要点评一下这道题。这个问题相比上次的问题,稍微的有那么点水平,但是还是不难看出面试官在刁难人。程序员需要懂的原理,应该是开发中的各种框架原理,如HashMap、Spring、Mybatis等,理解了原理才能更好的优化、扩展,以便于提高性能。而所谓的加减乘除原理并没有这些重要,往往在上大学的时候也就了解过了。加减乘除原理的理解对性能优化帮助并不大,即使位运算性能比减法和除法高,但是这点性能损耗,在我们服务器动辄4g8g的情况下是没有任何区别的。所以说面试的时候别问这种刁难人的问题啊,你就是造造火箭问问Spring也好!
*************************************优雅的分割线 **********************************

分享一波:程序员赚外快-必看的巅峰干货

如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程

请关注微信公众号:HB荷包
在这里插入图片描述
一个能让你学习技术和赚钱方法的公众号,持续更新

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/536996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pmc订单表格_复工了,读一则“如何提升订单准交率和生产效率”的真实故事

故事发生在中国南方小镇上一个做办公家具的公司……家具公司创建于1995年&#xff0c;是一家集研发、生产、销售、服务为一体的现代办公家具、酒店家具制造企业。主要产品有实木班台系列、会议台系列、职员桌系列、屏风系列、沙发系列、办公座椅、酒店家具系列。在省外还有两个…

GET和POST请求到底有什么区别?

分享一波:程序员赚外快-必看的巅峰干货 看到这个标题&#xff0c;想必大部分人都已经想关掉这篇博客了。先别急&#xff0c;你真的知道这两个的区别吗&#xff1f; 做过WEB开发的朋友可能很熟悉&#xff0c;看到这个问题能立马脱口而出二者的区别。 GET在浏览器回退时是无害的…

有赞电商云应用框架设计

背景 有赞是 SaaS 公司&#xff0c;向商家提供了全方位的软件服务&#xff0c;支撑商家进行采购、店铺、商品、营销、订单、物流等等管理服务。 在这个软件服务里&#xff0c;能够满足大部分的商家&#xff0c;为商家保驾护航。 但是很多大商家往往会有自己的特殊需求&#xff…

vivado 如何创建工程模式_基于Vivado的FPGA高性能开发研修班2019年8月30日上海举行...

一、课程介绍&#xff1a;从7系列FPGA开始&#xff0c;Xilinx提出了Vivado Design Suite设计软件&#xff0c;提供全新构建的SoC 增强型、以 IP 和系统为中心的下一代开发环境&#xff0c;以解决系统级集成和实现的生产力瓶颈。同时&#xff0c;Xilinx专门针对Vivado推出了Ultr…

程序员的自我修养——远离“外包思维”

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 在我们做开发的日子里&#xff0c;不免会进行跳槽&#xff0c;跳来跳去公司无非就分成两大类——互联网公司、外包公司。当然我们本次讨论的并…

英特尔为 Kubernetes 推出分布式深度学习平台:Nauta

2019独角兽企业重金招聘Python工程师标准>>> 随着人工智能的发展&#xff0c;深度学习的价值不断增长&#xff0c;但实现它可能是一个复杂耗时的过程。英特尔(Intel)正寻求通过其在 Kubernetes 进行分布式深度学习的新开源平台来改变这一状况&#xff0c;该深度学习…

pytorch梯度下降函数_Pytorch中常用的四种优化器SGD、Momentum、RMSProp、Adam

来源&#xff1a;AINLPer微信公众号编辑: ShuYini校稿: ShuYini时间: 2019-8-16 引言很多人在使用pytorch的时候都会遇到优化器选择的问题&#xff0c;今天就给大家介绍对比一下pytorch中常用的四种优化器。SGD、Momentum、RMSProp、Adam。随机梯度下降法&#xff08;SGD&#…

python计算无穷级数求和常用公式_傅里叶变换(二) 从傅里叶级数到傅里叶变换...

在上一部分当中&#xff0c;得到了利用三角函数表示周期函数的方法&#xff0c;但是对于非周期函数就...凉了。所以有什么办法吗&#xff1f;没办法&#xff08;划掉&#xff09;。这时候我们就需要拿出来我们的黑科技——傅里叶变换。一、傅里叶级数的推广当然这东西肯定不是凭…

中鸣投篮机器人怎么组装_1000余人参加洛阳市青少年机器人竞赛

机器人智能识别地面上的黑色线条&#xff0c;并沿着线条来到指定位置&#xff0c;放下“快递包裹”&#xff1b;无人机在空中飞舞&#xff0c;时而钻过圆环&#xff0c;时而来个空翻&#xff0c;犹如跳芭蕾般在空中划过一道优美曲线&#xff1b;橘红色乒乓球从筒道中送出&#…

Exchange队列优先级介绍和配置

一、场景 在日常办公环境中所有邮件都会存在重要与非重要的情况&#xff0c;并且不同的邮箱的使用人的级别也不一样&#xff0c;不一样的职位级别要求不一样的运维等级&#xff0c;以及发送邮件要求的速度也不一样。这就导致了邮件需要按照重要性进行分类&#xff0c;重要的邮件…

Mybatis源码阅读(一):Mybatis初始化1.3 —— 解析sql片段和sql节点

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

添加请求头 retrofit_RxJava 与 Retrofit 结合的最佳实践

前言RxJava和Retrofit也火了一段时间了&#xff0c;不过最近一直在学习ReactNative和Node相关的姿势&#xff0c;一直没有时间研究这些新东西&#xff0c;最近有个项目准备写&#xff0c;打算先用Android写一个Demo出来&#xff0c;却发现Android的世界发生了天翻地覆的变化&am…

Mybatis源码阅读(二):动态节点解析2.1 —— SqlSource和SqlNode

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

k8s边缘节点_边缘计算,如何啃下集群管理这块硬骨头?

导读边缘计算平台&#xff0c;旨在将边缘端靠近数据源的计算单元纳入到中心云&#xff0c;实现集中管理&#xff0c;将云服务部署其上&#xff0c;及时响应终端请求。然而&#xff0c;成千上万的边缘节点散布于各地&#xff0c;例如银行网点、车载节点等&#xff0c;节点数量甚…

Mybatis源码阅读(二):动态节点解析2.2 —— SqlSourceBuilder与三种SqlSource

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

搞懂toString()与valueOf()的区别

一、toString&#xff08;&#xff09; 作用&#xff1a;toString&#xff08;&#xff09;方法返回一个表示改对象的字符串&#xff0c;如果是对象会返回&#xff0c;toString() 返回 “[object type]”,其中type是对象类型。 二、valueOf( ) 作用&#xff1a;valueOf房啊发返…

oracle入库的速度能到多少_倒车入库别练复杂了,其实就这两点

教练总会让学员反复练倒车入库&#xff0c;但不少学员都会有这样的疑惑&#xff1a;为什么每一次倒库结果都不一样&#xff0c;倒车入库的练习重点是什么&#xff1f;倒车入库是科二的重点及难点&#xff0c;但只要掌握以下两个关键&#xff0c;顺利通过真不难&#xff1a;01方…

Mybatis源码阅读(三):结果集映射3.1 —— ResultSetBuilder与简单映射

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

kdj买卖指标公式源码_通达信指标公式源码MACD背离KDJ背离指标

N1:5;N2:10;N3:21;N4:60;牛熊:EMA(CLOSE,N4),COLORGREEN,LINETHICK3;DIFF:EMA(CLOSE,12) - EMA(CLOSE,26);DEA:EMA(DIFF,8);A1:BARSLAST(REF(CROSS(DIFF,DEA),1)); B1:REF(C,A11)>C AND REF(DIFF,A11)DRAWTEXT(IF(B1>0,1,0),L-0.1,MACD底背),COLORGREEN;RSV:(CLOSE-LLV(L…

Mybatis源码阅读(三):结果集映射3.2 —— 嵌套映射

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…