Java的移位运算

本文介绍了计算机的移位运算,包括左移和右移。左移是舍弃最高k位并在右端补k个0,右移分逻辑右移和算术右移。Java对右移有明确规定。通过实际例子,手动计算二进制执行过程,探究了Java中正数和负数的左、右移位运算的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

计算机支持两种移位运算,假设操作数为x,移动的位数为k,则向左移位是 x << k,向右移位是 x >> k。左移位会对输入的操作数舍弃最高的k位,并在右端补k个0。而右移位运算却分为两种情况,分别是逻辑右移和算术右移(也叫无符号右移和符号右移),在逻辑右移中,会对操作数舍弃最低的k位,并在左端补k个0,在算术运算中,则对操作数舍弃最低的k位,并在左端补k个最高有效位的值。

对于有符号数来说,最高位有效值是不同的,所以逻辑右移和算术右移将产生不同的效果,而C语言并没有明确定义有符号数该使用哪种类型的右移,虽然两种右移都可以,但是现在几乎所有的编译器/机器组合都会对有符号数使用算术右移。而Java比C强大的一个地方在于它对右移有明确的定义,规定 x >> k 使用算术右移, x >>> k 使用逻辑右移。

本文将通过几个实际的例子,并手动计算二进制执行过程,来探究当操作数分别为正数和负数时,Java的移位运算是怎么实现的。

左移位运算

左移运算也相当于做乘法运算,乘积因子为 2^k。例如,我们执行149 << 4,相当于执行了 149*16 = 2384。

1)正数左移位运算

System.out.println (149 << 4);
System.out.println (Integer.toBinaryString ( 149 << 4 ));
2384
100101010000

149 << 4 的计算过程如下:

输入:            149

转为二进制: 10010101

展开32位:       00000000 00000000 00000000 10010101

丢弃最高4位:  0000 00000000 00000000 10010101

右端补4个0: 0000 00000000 00000000 10010101 0000

忽略符号位: 10010101 0000

转为十进制: 2384

可以看出,我们计算过程的最后两步和程序打印效果完全一致。

2)负数左移位运算

System.out.println (-149 << 4);
System.out.println (Integer.toBinaryString ( -149 << 4 ));
-2384
11111111111111111111011010110000

-149 << 4 的计算过程如下:

输入:            -149

转为二进制: 11111111 11111111 11111111 01101011         (ps: 绝对值二进制取反再加1。)

丢弃最高4位:  1111 11111111 11111111 01101011

右端补4个0: 1111 11111111 11111111 01101011 0000

以上是个负数二进制,现要转成十进制,按照以下三步进行:

                       1111 11111111 11111111 01101010 1111      (减1)

                       0000 00000000 00000000 10010101 0000(取反)

                      -10010101 0000                                           (忽略符号位,并添负号)

转为十进制: -2384

可以看出,我们计算过程的第4步和最后一步的计算结果和程序打印效果完全一致。

右移位运算

右移运算也相当于做除法运算,被除数为 2^k。例如,我们执行149 >> 4,相当于执行了 149/16 = 9。

1)正数右移运算

Java的基本类型数据都是有符号数,最高位为1表示负数,最高位为0表示正数。所以对于正数来说,逻辑右移和算术右移没有任何区别,因为都是在左端补0。

System.out.println (149 >> 4);
System.out.println (Integer.toBinaryString ( 149 >> 4 ));
System.out.println (149 >>> 4);
System.out.println (Integer.toBinaryString ( 149 >>> 4 ));
9
1001
9
1001

149 >> 4 计算过程:

输入:            149

转为二进制: 10010101

展开32位:     00000000 00000000 00000000 10010101

丢弃最低4位:00000000 00000000 00000000 1001

左端补4个0:  0000 00000000 00000000 00000000 1001

忽略符号位:  1001

转为十进制:  9

149 >>> 4 的计算过程和上面完全一样,左端都是补4个0,所以打印效果当然是一致的。

2)负数右移运算

当输入的数据是负数,此时逻辑右移和算术右移将产生较大区别。由于负数高位是1,所以逻辑右移和算术右移在左端分别补0和1。

System.out.println (-149 >> 4 );  //负数的算术右移
System.out.println (Integer.toBinaryString ( -149 >> 4 ));
System.out.println (-149 >>> 4 ); //负数的逻辑右移
System.out.println (Integer.toBinaryString ( -149 >>> 4 ));
-10
11111111111111111111111111110110
268435446
1111111111111111111111110110

a)-149 >> 4 计算过程(负数的算术右移):

输入:           -149

转为二进制:   11111111 11111111 11111111 01101011         (ps: 绝对值二进制取反再加1。)

丢弃最低4位: 11111111 11111111 11111111 0110

左端补4个1:1111 11111111 11111111 11111111 0110

相应十进制:  -0000 00000000 00000000 00000000 0101   (ps: 减1,取反,添负号。)

转为十进制:-10

可以看出,我们第4步和第6步运算结果和代码打印的前两行完全一致。

b)-149 >>> 4 计算过程(负数的逻辑右移):

输入:               -149

转为二进制:    11111111 11111111 11111111 01101011       (ps: 绝对值二进制取反再加1。)

丢弃最低4位:  11111111 11111111 11111111 0110

左端补4个0: 0000 11111111 11111111 11111111 0110

转为十进制: 268435446

可以看出,我们第3步和第5步运算结果和代码打印的后两行完全一致。

### Java 中的位运算移位操作 #### 什么是移位运算移位运算是基于二进制数的操作方式之一,在编程领域中被广泛应用于优化性能和处理底层数据。Java 提供了三种主要的移位运算符:左移 (`<<`)、右移 (`>>`) 和无符号右移 (`>>>`)[^1]。 #### 各种移位运算符的功能描述 - **左移 (`<<`)** 左移运算符会将指定的数值向左移动指定的数量,相当于将其乘以 \(2^n\) 的效果(其中 n 是移动的位数)。高位会被丢弃,低位补零[^2]。 - **右移 (`>>`)** 右移运算符会将指定的数值向右移动指定数量的位数,对于负数而言,其最高位(符号位)会被保留并填充到左侧空缺位置;而对于正数,则会在左侧填入零。 - **无符号右移 (`>>>`)** 无论原数值是正是负,无符号右移都会在右侧移动的同时于左侧补充零,而不考虑原始符号位的状态[^2]。 #### 示例代码展示 以下是针对上述每一种移位运算的一个简单例子: ```java public class ShiftOperatorExample { public static void main(String[] args) { int num = 8; // Binary representation: 00001000 System.out.println("Original number: " + num); // Left shift example (equivalent to multiplying by 2) int leftShiftedNum = num << 1; System.out.println("Left shifted result: " + leftShiftedNum); // Output should be 16 // Right shift example with positive integer int rightShiftedPosNum = num >> 1; System.out.println("Right shifted result (positive): " + rightShiftedPosNum); // Output should be 4 // Unsigned right shift example int unsignedRightShiftedNum = -num >>> 1; System.out.println("Unsigned right shifted result (-8): " + unsignedRightShiftedNum); // Result depends on system architecture but typically large positive value. } } ``` #### 学习资源推荐 为了深入理解 Java 中的位运算及其应用,可以参考以下途径获取更多知识: - 官方文档或权威书籍如《Effective Java》等; - 在线教育平台上的专项课程,例如 Coursera 或 Udemy 上的相关主题培训; - 实践练习网站像 LeetCode, HackerRank 等提供大量涉及位运算的实际问题解决案例.
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alphathur

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值