只用位运算不用算术运算实现
题目
给定两个32位整数a和b,可正、可负、可0.不能使用算术运算符,分别实现a和b的加减乘除。
要求
如果给定的a和b执行加减乘除的某些结果本来就会导致数据的溢出,那么你实现的函数不必对那些结果负责。
基本思路
加法运算
使用位运算实现加法运算主要分为两个部分。先计算完全不考虑进位进行相加的结果,再计算只考虑进位的产生值。将两个结果相加就是最终的结果。
例如:
a: 001010101
b: 000101111
首先不考虑进位进行相加,结果为001111010,该结果其实就是a ^ b。
再考虑进位的产生值,结果为000001010,该结果其实就是(a & b)<< 1。
将1、2产生的结果再相加,此时依然要考虑两部分:不考虑进位和只考虑进位。
一直重复上述步骤,直到进位产生的值全部消失。
private int add(int a,int b){int sum = a;while(b!=0){sum = a^bb = (a&b) << 1a = sum}return sum}
减法运算
实现a - b只要实现a + (-b)即可。所以只要将a和b的相反数调用add函数就行。根据二进制数在机器中表达的规则,得到一个数的相反数,就是这个数的二进制数表达取反加1(补码)的结果
public int negNum(int n){return add(~n,1)
}public int minus(int a,int b){return add(a,negNum(b))
}
乘法运算
用位运算实现乘法运算。a × b的结果可以写成 a∗20∗b0+a∗21∗b1+...a∗2i∗bi+...a∗231∗b31a∗20∗b0+a∗21∗b1+...a∗2i∗bi+...a∗231∗b31. 其中bibi为0或1表示整数b的二进制表达中第i位的值(从右往左数)。该过程有点类似于求整数的N次方问题。具体实现参照如下代码
public int multi(int a,int b){int res = 0;while(b!=0){if((b&1)!=0){res = add(res,a);}a <<= 1;b >>= 1;}return res;
}
除法运算
用位运算实现除法运算其实就是乘法的逆运算。定义 res 表示除法的结果。首先将a向右移位31位,然后看能不能容下b,如果能,说明a/231a/231可以包含一个b,等价于a可以包含一个b∗231b∗231,令res的第31位为1,此时a的值应该为a−b∗231a−b∗231;如果不能容下b,令res的第31位为0,a的值不变;接下来将a向右移位30位是否能容下b……重复步骤直到a−b∗2i=0a−b∗2i=0。
以上过程只适用于a和b都不是负数的情况下,当a或b为负数时,可以先将a和b转成正数,计算完之后再判断res的真实符号就行。
除法实现到这一步已经可以解决绝大多数情况了。但是我们知道,32位最小整数的绝对值要比最大整数大,所以如果a或b等于最小值,是不能转换成相对应的正数的。这时候需要分情况考虑:
如果a和b都为最小值,直接返回1
如果a不为最小值,而b为最小值,那么a/b = 0,直接返回0
如果a为最小值,而b不为最小值。这时我们对a无能为力,但是我们可以让a增大一点点,计算出一个结果然后再修正一下就可以得到最终的结果。处理过程如下:
<1>计算(a+1)/b(a+1)/b,结果记为c
<2>计算c∗bc∗b
<3>计算(a−c∗b)/b(a−c∗b)/b,结果记为rest
<4>计算c+rest
public boolean isNeg(int n){return n<0;
}public int div(int a,int b){int x = isNeg(a) ? negNum(a):a;int y = isNeg(b) ? negNum(b):b;int res = 0;for (int i = 31;i>-1;i=minus(i,1)){if ((x>>i)>=y){res |= (1<<i);x = minus(x,y<<i);}}return isNeg(a)^isNeg(b) ? negNum(res):res;
}public int divide(int a,int b){if(b==0){throw new RuntimeException("divisor is 0");}if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE){return 1;}else if (b == Integer.MIN_VALUE){return 0;}else if (a == Integer.MIN_VALUE){int res = div(add(a,1),b);return add(res,div(minus(a,multi(res,b)),b));}else{return div(a,b);}
}
只用位运算不用算术运算实现相关推荐
- 只用位运算来实现整数的加减乘除四则运算
首先回忆计算机组成原理学过的内容,数字在机器ALU运算逻辑单元内部是以补码形式进行运算的,因为补码有两个优势: 1.能做到符号位和数值部分一起运算,这样无需单独考虑符号. 2.能把减法运算转化为加法运 ...
- 位运算常用技巧分析汇总(算法进阶)
文章目录 运算性质 异或运算的一些性质 秀秀伸手 1.只用位运算来完成两个整数相加 2.不用临时变量,交换a.b两个数的值 3.判断一个数是奇数还是偶数 3.快速计算2*n.2*n+1和n/2 4.` ...
- 用位运算完成大小比较
目录 只用位运算完成大小比较 写在后面 只用位运算完成大小比较 如何不用任何比较判断语句,就可以返回两个数中较大的那个 /*** @author 杨思远* @version 1.0* @title 位 ...
- 位运算详解+竞赛常见用法总结
目录 一.位运算详解 二.位运算应用 1.快速幂 2.给定一个数组A, 长度为n,求下面这段程序的值 3.数数字 4.数数字 2 5.nim博弈问题: 6.树状数组 7.判断一个数x是不是2的某次方 ...
- 位运算简介及实用技巧(二):进阶篇(1)
===== 真正强的东西来了! ===== 二进制中的1有奇数个还是偶数个 我 们可以用下面的代码来计算一个32位整数的二进制中1的个数的奇偶性,当输入数据的二进制表示里有偶数个数字1 ...
- 位运算(转自matrix67)
http://www.matrix67.com/blog/archives/263 (原文链接) 什么是位运算? 程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内 ...
- 剑指 Offer 65. 不用加减乘除做加法(位运算、递归、迭代)
一.题目 剑指 Offer 65. 不用加减乘除做加法 题目描述 写一个函数,求两个整数之和,要求在函数体内不得使用 "+"."-"."*" ...
- 超简单的位运算---再也不用担心看不懂题解了
超简单的位运算---再也不用担心看不懂题解了 写在前面 1.原码.反码与补码------整形在计算机中的储存 2.移位操作符 3.位操作符 4.小练手 写在最后 写在前面 大家好,这里是风扇的小小笔记 ...
- [GO语言基础] 四.算术运算、逻辑运算、赋值运算、位运算及编程练习
作为网络安全初学者,会遇到采用Go语言开发的恶意样本.因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识:另一方面是分享与读者,希望大家一起进步.前文介绍了Golang的 ...
最新文章
- 这道「传说级」的数学题,为什么有 3 个正确答案?
- 读书笔记-我所理解的生活
- SAP云平台 Document Information Extraction服务测试
- android 5.0 设置铃声,android5.0联系人铃声设置和来电读取分析
- c语言素数程序出现大空行,C语言实现寻找大素数
- html-iframe_HTML iframe
- 客户端跳转与服务器跳转的区别
- Objective-C和C++混编的要点
- 腾讯二面:引入RabbitMQ后,你如何保证全链路数据100%不丢失 ?
- latex导数_使用LaTeX语法编写数学公式(持续更新)
- 五笔字根表识别码图_五笔输入法口诀(五笔字根表快速记忆图)
- 群晖让usb打印机变成网络打印机
- Spark学习:Win10中编译Spark源码
- html 静止横屏_移动端开发-禁止横屏
- Endnote实用快捷键
- ELK之Kibana入门及使用
- 虾皮 店铺如何获取免费流量?5种引流量办法
- EMC磁珠到底什么样的特性
- java是高级还是低级语言_程序员:高级与低级编程语言,您应该学习哪些内容?...
- MTTF,MTBF,MTRF的概念
热门文章
- Centos7 Docker Jenkins ASP.NET Core 2.0 自动化发布和部署
- jQuery和AngularJS的区别小分析
- HBase 6、用Phoenix Java api操作HBase
- Lync Server 2013与OWA的集成
- JAVA 对象引用,以及对象赋值
- XP系统限制修改IP有新招
- 构造函数的初始化,初始化列表还是大括号里好,那种效率高
- Linux MySQL Connector/C++ 编程实例
- 浅谈安卓线程池相关问题
- laravel php配置,PHP Laravel框架路由配置及设置技巧全解