Java中的位运算

news2024/12/25 9:22:57

文章目录

    • Java中支持的位运算
    • 位运算规则
    • 逻辑运算
      • 与运算(&)
      • 或运算(|)
      • 异或运算(^)
      • 取反运算(~)
    • 位移操作
      • 左移(<<)
      • 右移(>>)
      • 无符号右移(>>>)
    • 位运算的使用奇巧淫技
      • 判断奇偶数
      • 获取二进制位是1还是0
      • 交换两个整数变量的值
      • 不用判断语句,求整数的绝对值
    • 常见面试题

Java中支持的位运算

  1. 位与(&):二元运算符,两个为1时结果为1,否则为0
  2. 位或(|):二元运算符,两个其中有一个为1时结果就为1,否则为0
  3. 位异或(^):二元运算符,两个数同时为1或0时结果为1,否则为0
  4. 位取非(~):一元运算符,取反操作,即1变为0,0变为1
  5. 左移(<<):一元运算符,按位左移一定的位置。高位溢出,低位补0,符号位不变。
  6. 右移(>>):一元运算符,按位右移一定的位置。高位补符号位,符号位不变,低位溢出。
  7. 无符号右移(>>>):一元运算符,高位补零,低位溢出。

位运算规则

计算机对于计算数据的话,都是以二进制来进行运算的,所以使用位运算相比直接使用(+、-、 *、/)运算符,要更高效,能显著调高代码在计算机中的执行效率。

对于有符号的而言,

  • 最高位为符号位,0表示正数,1表示负数
  • 正数的原码,反码和补码都一样,三码合一
  • 负数的反码:符号位保持不限,其他位取反
  • 负数的补码:反码 + 1
  • 0的反码和补码都是0
  • 数据存储和运算都是以补码的方式进行的

下面以 -1 为例子展示原码、反码和补码的转换关系(以int数据类型为例,int类型在Java中占4字节):

在这里插入图片描述

逻辑运算

与运算(&)

两个数相同位置的比特进行与运算,若两个位置均为1,那么结果就为1,否则为0

计算 a = 4 & -5

​ 因为4为正数,所以原码和补码相同,即4的补码为:00000000 0000000 00000000 00000100

因为-5为负数,所以需要进行原码 -> 反码 -> 补码的转换。转换步骤如下:

1)原码:10000000 00000000 00000000 00000101

2)反码:11111111 11111111 11111111 11111010

3)补码:11111111 11111111 11111111 11111011

将4和-5的补码进行 & 运算得到补码结果:00000000 0000000 00000000 00000000

所以最终结果:a = 0(0的反码和补码都是0)

或运算(|)

两个数相同位置的比特进行或运算,若两个位置其中一个为1则结果为1,否则为0

计算 a = -2 | 5

因为-2为负数,所以需要进行原码 -> 反码 -> 补码的转换。转换步骤如下:

1)原码:10000000 00000000 00000000 00000010

2)反码:11111111 11111111 11111111 11111101

3)补码:11111111 11111111 11111111 11111110

因为5为正数,补码和反码一致,所以5的补码为:00000000 00000000 00000000 00000101

将-2 和 5 的补码进行 | 运算得到补码结果:11111111 11111111 11111111 11111111

结果显然是一个负数,而负数的补码和原码不一致,所以需要将补码结果转换为原码才能得到最终的结果

补码转原码的过程是跟原码转补码相反的过程,具体过程如下:

1)补码:11111111 11111111 11111111 11111111

2)补码 -1 得到反码:11111111 11111111 11111111 11111110

3)符号位不变,其他位置取反得原码:10000000 00000000 00000000 00000001

所以最终结果:a = -1

异或运算(^)

两个数相同位置的比特进行异或运算,若两个数均为0或1,则结果为0,否则为1

计算 a = 1 ^ -5

​ 1的补码为:00000000 00000000 00000000 00000001

-5的补码为:11111111 11111111 11111111 11111011

两个补码进行 ^ 运算得到补码结果:11111111 11111111 11111111 11111010

补码为负数,需要转换成原码:

1)补码:11111111 11111111 11111111 11111010

2)反码:11111111 11111111 11111111 11111001

3)原码:10000000 00000000 00000000 00000110

​ 所以最终结果:a = -6

取反运算(~)

若位数为0,则取反后为1,若为1,取反后为0

计算 a = ~2

​ 2的原码为:00000000 00000000 00000000 00000010

2的补码为:00000000 00000000 00000000 00000010

取反:11111111 11111111 11111111 11111101

取反后的结果仍为补码,此时补码为负数,则需要转成原码

​ -1 得到反码:11111111 11111111 11111111 11111100

​ 符号位不变,其他位置取反得到原码为:10000000 00000000 00000000 00000011

​ 所以最终结果:a = -3

位移操作

Java中的位移操作只针对int类型的有效,Java中,一个int的长度始终是32位,也就是4个字节,它操作的都是该整数的二进制数。也可作用于以下类型,即 byte,short,char,long(它们都是整数形式)。当为这四种类型时,JVM先把它们转换成int类型再进行操作。

左移(<<)

高位溢出,低位补0,符号位不变。移动位数超过该类型的最大位数,则进行取模,如对Integer型左移34位,实际上只移动了两位。左移一位相当于乘以2的一次方,左移n位相当于乘以2的n次方。

正数 a = 20 << 2

​ 20的二进制补码:00000000 00000000 00000000 00010100

​ 向左移动两位后: 00000000 00000000 00000000 01010000

​ 结果: a = 80

负数 a = -20 << 2

​ -20的二进制原码:10000000 00000000 00000000 00010100

​ -20的二进制反码:11111111 11111111 11111111 11101011

​ -20的二进制补码:11111111 11111111 11111111 11101100

​ 左移两位后的补码:11111111 11111111 11111111 10110000

​ 反码:11111111 11111111 11111111 10101111

​ 原码:10000000 00000000 00000000 01010000

​ 结果:a = -80

右移(>>)

高位补符号位,符号位不变,低位溢出右移一位相当于除以2的一次方,右移n位相当于除以2的n次方。除不尽向下取整。

正数:a = 20 >> 2

20的二进制补码:00000000 00000000 00000000 00010100

向右移动两位后:00000000 00000000 00000000 00000101

结果:a = 5

负数:r = -20 >> 2

-20 的二进制原码 :10000000 00000000 00000000 00010100

-20 的二进制反码 :11111111 11111111 11111111 11101011

-20 的二进制补码 :11111111 11111111 11111111 11101100

右移两位后的补码:11111111 11111111 11111111 11111011

反码:11111111 11111111 11111111 11111010

原码:10000000 00000000 00000000 00000101

结果:r = -5

无符号右移(>>>)

高位补零,低位溢出。即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0

正数:a = 20 >>> 2 与 a = 20 >> 2相同

​ 结果:a = 5

负数 a = -20 >>> 2

​ -20的二进制原码:10000000 00000000 00000000 00010100

​ -20的二进制反码:11111111 11111111 11111111 11101011

​ -20的二进制补码:11111111 11111111 11111111 11101100

​ 右移两位后的补码:00111111 11111111 11111111 11111011 (正数的原码、反码、补码都是一样)

​ 反码:00111111 11111111 11111111 11111011

​ 原码:00111111 11111111 11111111 11111011

​ 结果:a = 1073741819

位运算的使用奇巧淫技

判断奇偶数

int num = 5;
System.out.println(num + "是" + ((num&1) == 0 ? "偶数":"奇数"));

5的二进制代码为101,1的二进制代码为001,5 & 1 就是 101 & 001

我们通过二进制判断奇偶数的话,看的是二进制最后一位,如果最后一位为0的话是偶数,为1的话是奇数

为什么?因为二进制除了最后一位,其他位都是2的幂次方,必然是偶数,所以我们通过判断最后一位是0或者1 就可以判断是奇数还是偶数。

获取二进制位是1还是0

int n = 86;
System.out.println(n + "的第五位是" + (((n&(1<<4))>>4) == 0 ? "0":"1"));
System.out.println(n + "的第五位是" + (((n>>4)&1) == 0 ? "0":"1"));

交换两个整数变量的值

int num1 = 10;
int num2 = 20;
num1 = num1^num2;
num2 = num1^num2;
num1 = num1^num2;
System.out.println("num1=" + num1 + ", num2=" + num2);

异或运算满足的性质:

  1. 可交换性:ab=ba
  2. 可结合性:abc=(ab)c=a(bc)
  3. 自身进行异或运算值为零:a^a=0
  4. 与 0 异或时结果不变:a^0=a

num2可以看成是num1(num2num2),故结果为num1

num1可以看成是(num1num1)(num2num2)num2,故结果为num2

不用判断语句,求整数的绝对值

int a = -10;
int b = ((a >> 31) ^ a) + (a >>> 31);
System.out.println("a=" + a + ", b=" + b);

先来分析一下 a = -86:

原码:10000000 00000000 00000000 01010110

反码:11111111 11111111 11111111 10101001

补码:11111111 11111111 11111111 10101010

取反:00000000 00000000 00000000 01010101

(+1): 00000000 00000000 00000000 01010110

由此可以得出,负数的绝对值为,补码取反+1,即 ~a+1。

int a = -86;
int b = ~a + 1;
System.out.println(b);

但是,这个还不能达到题目所要求的,不用判断,当假定 a = -86的时候,就已经知到 a 是负数了。

分析:任何一个数 异或0 结果为其本身,异或-1 (二进制全为1) 相当于取反

而一个32 bit的int类型的正数 >> 31,结果为0,负数 >> 31 为-1。

即 (a >> 31) 的结果为 0 或者 -1。如果 a 为负数,(a >> 31) ^ a 相当于 ~a,则需要 + 1 才能得到 a 的绝对值

且一个32 bit的int类型的正数 >>> 31,结果为0,负数 >>> 31为1。

所以代码为:((a >> 31) ^ a) + (a >>> 31)

也可以写成:

int a = -86;
int b = a >> 31;
// 当a为正时:b = 0,a ^ b = a;
// 当a为负时:b = -1,a ^ b = ~a;
return (a ^ b) - b; // 也可以写为:(a ^ (a >> 31)) - (a >> 31)

常见面试题

Q:2*8怎么运算性能最好

A:我当时遇到这个面试题的时候是懵的,直接回答两个new BigDecimal();再进行运算就行了。*实际采用位运算的方式是性能最好的,因为计算机对于计算数据的话,都是以二进制来进行运算的,所以使用位运算相比直接使用(+、-、 、/)运算符,要更高效,能显著调高代码在计算机中的执行效率。相当于2 << 3。


Q:怎么交换两个整数变量的值

A:我当时遇到这个面试题的时候也是懵的,不知道这题的考点是啥,直接回答:创建一个临时变量,把其中一个变量赋值给临时变量,然后再把另一个变量赋值给这个变量,最后把临时变量赋值给另一个变量。实际直接采用异或运算即可,具体可见奇巧淫技中的交换两个整数变量的值

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

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

相关文章

十五周算法训练营——BFS

今天是十五周算法训练营的第六周&#xff0c;主要讲BFS专题。&#xff08;欢迎加入十五周算法训练营&#xff0c;与小伙伴一起卷算法&#xff09; 「BFS的核心思想是把一些问题抽象成图&#xff0c;从一个点开始&#xff0c;向四周开始扩散。一般来说&#xff0c;写BFS算法都是…

3-Raven2百个靶机渗透(精写-思路为主)

特别注明&#xff1a;本文章只用于学习交流&#xff0c;不可用来从事违法犯罪活动&#xff0c;如使用者用来从事违法犯罪行为&#xff0c;一切与作者无关。 文章目录 前言一、信息收集二、ssh爆破尝试三、根据框架exp和cve拿shell四、对mysql的进一步渗透&#xff0c;mysql UD…

Python - 通过 pyInstaller 打包成可执行文件

一、场景 通常来说&#xff0c;我们开发的 python 脚本一般都会用到一些第三方的包&#xff0c;并且需要对应版本的 python 解释器。因此在 python 脚本在不同的主机上运行的时候相对来说不是很方便&#xff0c;为此可以通过 pyInstaller 将脚本和解释器打包成可执行文件&…

数字中国创新大赛·信创赛道优秀作品推荐 | 国产工业实时操作系统(Intewell)

产品介绍和功能体系 Intewell工业实时操作系统源于有30多年发展历史的“道”操作系统&#xff0c;是一款微内核实时操作系统&#xff08;RTOS&#xff09;&#xff0c;具有良好的可扩展性、友好的用户开发环境和丰富的开发调试工具&#xff0c;提供POSIX接口。Intewell工业实时…

2023年5月产品经理认证NPDP线上班,我要报名学习

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

程序设计的三种结构-C中实现其的6条语句

什么是程序设计结构? C语言设计出来就是为了解决现实中存在的问题&#xff0c;但是现实中问题大多较为复杂&#xff0c;如何描述问题也成为了一个重要的问题。将这些众多的问题核心找出来&#xff0c;我们发现只需要使用三种基本的结构包括&#xff1a;顺序结构&#xff0c;分…

FS4068四节锂电池充电管理控制芯片

FS4068 是一款工作于 2.7V 到 6.5V 的 PFM 升压型四节锂电池充电控制集成电路。 FS4068采用恒流和恒压模式对电池进行充电管理&#xff0c;内部集成有基准电压源&#xff0c; 电感电流检测单元&#xff0c;电池电压检测电路和外置场效应晶体管驱动电路等&#xff0c; 具有外部元…

面向开发者的 ChatGPT 提示工程

LLM 正在逐步改变人们的生活&#xff0c;而对于开发者&#xff0c;如何基于 LLM 提供的 API 接口快速、便捷地开发一些具备更强能力、集成 LLM 的应用&#xff0c;来便捷地实现一些更新颖、更实用的能力&#xff0c;是一个急需学习的重要能力。由巨佬吴恩达老师与 OpenAI 合作推…

Golang每日一练(leetDay0060) 多数元素、两数之和III

目录 169. 多数元素 Majority Element &#x1f31f; 170. 两数之和 III Two-sum-iii-data-structure-design &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏…

Zynq实现SDI视频解码PCIE传输 提供工程源码和QT上位机源码加技术支持

目录 1、前言2、我已有的SDI编解码方案3、我已有的PCIE方案4、基于zynq架构的PCIE5、总体设计思路和方案SDI摄像头Gv8601a单端转差GTX解串SDI解码VGA时序恢复YUV转RGB图像缓存PCIE发送通路SDI同步输出通路 6、vivado工程详解7、驱动安装8、QT上位机软件9、上板调试验证SDI同步H…

VMware虚拟机克隆、复制虚拟机

文章目录 为什么要克隆一、环境检查二、开始克隆三、网卡静态配置 为什么要克隆 首先VMware 上创建的虚拟机是可以重复使用的&#xff0c;安装好的虚拟机可以直接复制或者剪切到其它任意电脑上&#xff0c;然后使用 VMware 打开使用&#xff0c;两者的虚拟机设置以及登录密码都…

MySQL笔记(二) 数据库操纵语言DML 、数据库查询语言DQL、数据库控制语言DCL、计算字段、子查询、函数

MySQL笔记&#xff08;二&#xff09; 数据库操纵语言 DML插入数据 INSERT修改数据 UPDATE删除数据 DELETE 数据库查询语言DQL单表查询常用查询条件排序查询分组和分页查询限制结果 分页查询多表查询自身连接查询外连接查询嵌套查询 计算字段字段 field拼接 concatenateTrim()…

10个免费的ChatGPT镜像网站

文章目录 前言说明网站 前言 ChatGPT是一种基于OpenAI GPT&#xff08;Generative Pretrained Transformer&#xff09;模型的聊天机器人&#xff0c;它可以对用户提出的问题做出回答&#xff0c;同时还能够进行精准的语言理解和回复&#xff0c;较好地满足了人们与机器人之间…

MySQL数据库基础表格——增删改查(下)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️树高千尺&#xff0c;落叶归根人生不易&…

媒体邀约服务

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体邀约是什么&#xff1f;专业的媒体邀约服务包含哪些内容&#xff1f;怎么选择合适的媒体邀约服务机构&#xff1f; 今天胡老师就跟大家分享下这方面你的经验。 一&#xff0c;媒体邀…

【C++STL】AVL树

前言 二叉搜索树是具有特殊存储结构的树&#xff0c;任意根节点的左子树的所有节点值都比根节点的值小&#xff0c;右子树的所有节点值都比根节点大。 这种特殊的存储结构使得查找的效率大大提升&#xff0c;为logN。但是还有缺陷。 因为二叉搜索树的构建是一个节点一个节点的…

django 过往后端搭建笔记整理 (2)--rest_framework视图使用

rest_framework视图使用 CreateAPIView---单独执行post上传逻辑views.pyuser_serializers.py CreateAPIView—单独执行post上传逻辑 基本逻辑&#xff1a; ① 准备视图函数类 ② 准备序列化器类 &#xff08;其中可以自定义如何序列化数据、序列化哪些数据&#xff0c;以及如何…

苹果最近删除的照片删除怎么恢复?专业人士都这样恢复照片!

案例&#xff1a;苹果照片删除了怎么恢复&#xff1f; 【友友们&#xff0c;最近不小心清空了手机照片&#xff0c;在最近删除没有看到&#xff0c;有什么方法可以找回来吗&#xff1f;】 随着现代科技的不断发展&#xff0c;手机已经成为人们生活中必不可少的物品&#xff0c…

设计模式 -- 享元模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

以CSDN为例,用Charles抓浏览器接口

0 描述 很多网站&#xff0c;都禁止F12&#xff0c;这就给抓包设置了门槛&#xff0c;虽然解决的方法有很多&#xff0c;今天尝试使用工具试一试&#xff0c;以CSDN热榜为例&#xff0c;直接转python代码 1 工具下载 工欲善其事&#xff0c;必先利其器 这个我就不多说&#x…