位运算实现加减乘除四则运算(Java)
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
本文是继《一文了解有趣的位运算》的第二篇文章.
我们知道,计算机最基本的操作单元是字节(byte),一个字节由8个位(bit)组成,一个位只能存储一个0或1,其实也就是高低电平。无论多么复杂的逻辑、庞大的数据、酷炫的界面,最终体现在计算机最底层都只是对0101的存储和运算。因此,了解位运算有助于提升我们对计算机底层操作原理的理解。
一、加法
两个二进制数异或运算的结果是不考虑进位时的结果,
两个二进制数与运算的结果中含有1的位是有进位的位。
以0101 + 0001 = 0110为例分析如下:
//计算 0101 + 0001
0101 ^ 0001 = 0100 //异或结果表明,如果不考虑进位,那么结果为0100
0101 & 0001 = 0001 //与运算结果表明,最低位需要向次低位进1
0001 << 1 = 0010 //与运算结果左移一位,将进位加到高位上
//递归计算 0100 + 0010,直到+号右侧数字为0
java代码:
递归
public static int add(int a, int b) {
if (b == 0) {
return a;
} else {
return add(a ^ b, (a & b) << 1);
}
}
循环
public static int add2(int a, int b) {
int sum = a;
while (b != 0) {
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
二、减法
与加法的思路一致,只不过减去一个数等于加一个数的相反数。
例如:5-1 = 5+(-1)。所以,我们只需要求出被减数的相反数即可。
如何求出一个数的相反数?
计算机中存储的是二进制的补码形式,正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1。
例如:
1在计算机中的二进制表示为:0000 0001
-1在计算机中的二进制表示为:1111 1111
计算过程为:
-1的原码:1000 0001
-1的反码:1111 1110
-1的补码:1111 1111
其中,由1的原码(0000 0001)取反可得-1的反码(1111 1110)
总结,一个数的相反数的求法就是该数每一位取反,末位加一。
java代码:
public static int minus(int a, int b) {
return add(a, add(~b, 1));
}
三、乘法
如果没有思路,可以先在纸上笔算二进制乘法的过程:
0101 a
0110 b
------------
0000
101
01
0
------------
11110
梳理下笔算二进制乘法的过程:
初始化乘积结果为0,依次遍历数字b的末位 0→1→1→0,当末位为0时,乘积结果加上0,也就是乘积不变,A左移一位;当末位为1时,乘积结果加上A,A再左移一位。
如何遍历数字b的末位呢?
根据前面所学,我们可以使用与运算取一个数的末位,并不断右移数字b,直到数字b==0,即可结束位移。
需要注意的是正负数的符号问题,此处是先对a、b两数的绝对值计算其乘积,最后再确定其符号。
java代码为:
public static int multiply(int a, int b) {
//将乘数和被乘数都取绝对值
int A = a < 0 ? add(~a, 1) : a;
int B = b < 0 ? add(~b, 1) : b;
//计算绝对值的乘积
int P = 0;
while (B != 0) {
if ((B & 1) != 0) { //取乘数的二进制的最后一位,0 or 1
P = add(P, A);
}
A = A << 1;
B = B >> 1;
}
//计算乘积的符号
if ((a ^ b) < 0) {
P = add(~P, 1);
}
return P;
}
四、除法
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
最简单的除法实现就是不停的用除数去减被除数,直到被除数小于除数时,此时所减的次数就是我们需要的商,而此时的被除数就是余数。
唯一需要注意的就是商的符号和余数的符号。商的符号确定方式也乘法是一样,即同号为正,异号为负。而余数的符号和被除数的符号是一样的。
和简单的乘法实现一样,这里我们要先对两数的绝对值求商,求余数。最后再确定符号。
public static int[] divide(int a, int b) {
//对被除数和除数取绝对值
int A = a < 0 ? add(~a, 1) : a;
int B = b < 0 ? add(~b, 1) : b;
//对被除数和除数的绝对值求商
int C = A; // 余数C
int N = 0; // 商N
while (C >= B) {
C = minus(C, B); // C-B
N = add(N, 1); // N+1
}
// 求商的符号
if ((a ^ b) < 0) {
N = add(~N, 1);
}
// 求余数的符合
if (a < 0) {
C = add(~C, 1);
}
return new int[]{N, C};
}
需要指出的是,这种算法在A很大、B很小的情况下效率很低,那该如何优化算法减少while循环的次数呢?
不难想到,除法是由乘法的过程逆推而来的。例如 9÷4=2...1,也就是2*4+1=9。假设用9去减4*2,可以得出结果等于1,因为1小于4,那么就可以得出9÷4的商是2,余数是1。
如何确定4的倍数是逼近最终结果的关键。我们知道,int 整型有32位,除首位表示符号位,每一位的大小是 [2^0, 2^1, 2^2, , , 230],最大的int整数是231-1。所以,我们可以依次将被除数与2^31, 2^30, ...2^3, 2^2, 2^1, 1相乘,如果除数大于它们的乘积,除数就与之相减,并用相减得到的余数继续作为除数,直到循环结束。
java代码:
public static int[] divide(int a, int b) {
// 对被除数和除数取绝对值
int A = a < 0 ? add(~a, 1) : a;
int B = b < 0 ? add(~b, 1) : b;
int N = 0; // 商 N
for (int i = 31; i >= 0; i--) {
// 未使用A>=(B<<i)进行判断,因为只有左移B时舍弃的高位不包含1,才相当于该数乘以2的i次方.
if ((A >> i) >= B) { // A ÷ 2^i >= B
N += (1 << i); // N = N + 2^i
A -= (B << i); // A = A - B*2^i
}
}
int C = A; // 余数C
// 求商的符号
if ((a ^ b) < 0) {
N = add(~N, 1);
}
// 求余数的符号
if (a < 0) {
C = add(~C, 1);
}
return new int[]{N, C};
}
版权声明
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

位运算实现加减乘除四则运算(Java)的更多相关文章
- 用Java位运算实现加减乘除四则运算
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6412875.html 感谢博客:http://blog.csdn.net/itismelzp/article/ ...
- Java位运算实现加减乘除四则运算
本文是继<一文了解有趣的位运算>的第二篇文章. 我们知道,计算机最基本的操作单元是字节(byte),一个字节由8个位(bit)组成,一个位只能存储一个0或1,其实也就是高低电平.无论多么复 ...
- Java位运算实现加减乘除
一.加法 a+b 举例实现:13+9=22 13+9不考虑进位结果为12 只考虑进位结果为10 和刚好是22. 13二进制为1101,9二进制为1001. 不考虑进位结果为0100.算式为a^b 只考 ...
- 【C++】位运算实现加减乘除
#include<iostream> #include<assert.h> using namespace std; // 位运算实现加减乘除 int myAdd(int nu ...
- 我们必须要了解的Java位运算(不仅限于Java)
本文原创地址为 https://www.cnblogs.com/zh94/p/16195373.html 原创声明:作者:陈咬金. 博客地址:https://www.cnblogs.com/zh94/ ...
- 用位运算实现四则运算之加减乘除(用位运算求一个数的1/3) via Hackbuteer1
转自:http://blog.csdn.net/hackbuteer1/article/details/7390093 ^: 按位异或:&:按位与: | :按位或 计算机系统中,数值一律用补码 ...
- php实现不用加减乘除号做加法(1、善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍)
php实现不用加减乘除号做加法(1.善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍) 一.总结 1.善于寻找资源:去搜为什么位运算可以实现加法,里面讲的肯定要详细一万倍 二.ph ...
- Java位运算总结:位运算用途广泛《转》
前天几天研究了下JDK的Collection接口,本来准备接着研究Map接口,可是一查看HashMap类源码傻眼咯,到处是位运算实现,所以我觉得还是有必要先补补位运算知识,不然代码看起来有点费力.今天 ...
- Java中的二进制及基本的位运算
Java中的二进制及基本的位运算 二进制是计算技术中广泛采用的一种数制.二进制数据是用0和1两个数码来表示的数.它的基数为2,进位规则是"逢二进一",借位规则是"借一当二 ...
随机推荐
- [JavaWeb基础] 013.Struts2 自定义类型转换器
很多时候,我们在做web开发的时候经常要用到时间的转换器,Struts2给我们提供了一种类型转换器的接口.下面我们讲讲怎么实现吧. 1.首先我们要定义一个类型转换的类,继承自com.babybus.s ...
- C#线程 线程进阶
第四部分:高级线程 非阻塞同步 前面我们说过,即使在分配或增加字段的简单情况下,也需要同步.尽管锁定始终可以满足此需求,但是竞争性锁定意味着线程必须阻塞,从而遭受上下文切换的开销和调度的延迟,这在高度 ...
- 【Mybatis】mybatis3入门
mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可 ...
- JPA入门及深入
一:ORM介绍 ORM(Object-Relational Mapping) 表示对象关系映射.在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中.只要有一套程序能够做到建立对象与数 ...
- unittest单元测试框架入门及应用
一.简介 unittest是Python单元测试框架.unittest它支持自动化测试,在测试中使用setup(初始化)和shutdown(关闭销毁)操作,组织测试 用例为套件(批量运行),以及把测试 ...
- LoadRunner性能测试笔试/面试题
客户交付一个性能测试项目,请阐述你的实施流程. 测试设计阶段: 1)了解被测系统的性能需求,定义测试目标和范围: 2)了解系统的技术信息,如系统架构等: 3)确定测试方案.进度安排,并制定测试计划,场 ...
- iOS-自定义Model转场动画-仿酷我音乐播放器效果
周末,闲来无事,仿写了酷我音乐播放器效果: 效果图如下: 实现思路: 1.实现手势处理视图旋转 2.自定义Model动画: 1.手势是利用了一个UIPanGestureRecognizer手势: 注意 ...
- iOS-地图定位 && 解码与反解码
前段时间,公司开发的App用到了地图和定位,所以记录一下,作为回顾总结. 对于地图和定位,苹果公司提供给了两个框架: MapKit:用于地图展示 Core Location ...
- 第12章 Java内存模型与线程
参考<深入理解Java虚拟机> 一.Java内存模型 1.Java内存模型 2.内存间交互操作 流程图: 3.volatile关键字 两个特性: 3.1.保证变脸对所有线程的可见性: 由 ...
- 在WinForms里嵌入MediaPlayer的一些版本问题, tlbimp导入, 以及不导入而纯用C#+字符串来动态调用.
网上很多写使用WindowsMediaPlayer WMP控件的文章. 大多数都是从工具栏或COM导入. 最近正在做的CEF整合Asp.Net Core Blazor server side的过程中, ...