指令系统和计算机体系结构——移位运算

前言

在二进制运算中,移位运算符用于将二进制位整体移动指定的位数。常见的移位运算符有三种:左移、右移和无符号右移,它们的行为和适用场景有所不同。

为了便于理解,本文会讲十进制和二进制进行转换,来方便大家更好的理解这个计算的过程。
{10}:表示十进制的数据。如8{10}表示十进制的8
{2}:表示二进制的数据。0000 1000{2}表示二进制的8

1. 左移运算符(<<)

  • 定义:将二进制位向左移动指定的位数,右侧补零。
  • 示例:
    数字 6 的二进制是 0000 0110,左移 2 位后变为 0001 1000(即十进制的 24)。
    
  • 数学意义:相当于乘以 2n ,n为移动的位数),但可能溢出。
  • 注意:左移运算在所有语言中行为一致。

溢出情况详解

对于这个溢出的情况,下面做一个详细的解释,顺便讲解一下这个过程中计算机是如何计算数据的。
下面将结合具体例子详细讲解溢出问题,以及二进制原码、反码、补码的转换和结果转回十进制的过程。

下面将结合具体例子详细讲解溢出问题,以及二进制原码、反码、补码的转换和结果转回十进制的过程。

1. 数据表示基础

在计算机里,整数一般用二进制来表示。有符号整数常用原码、反码和补码来表示。

  • 原码:最高位是符号位(0 代表正数,1 代表负数),其余位表示数值大小。
  • 反码:正数的反码和原码一样;负数的反码是原码除符号位外其余位取反。
  • 补码:正数的补码和原码一样;负数的补码是反码加 1。

2. 溢出问题示例(以 4 位二进制为例)

加法溢出
  • 十进制计算:计算 7 + 2
  • 二进制转换与计算
    • 原码
      • 7 的原码是 0111
      • 2 的原码是 0010
    • 补码(正数补码和原码相同)
      • 7 的补码是 0111
      • 2 的补码是 0010
    • 补码相加0111 + 0010 = 1001
    • 溢出判断:这里出现了溢出,因为结果的符号位变成了 1,这表明结果是负数,但两个正数相加结果不应该是负数。
    • 结果转回十进制
      • 因为 1001 是补码,先求反码(补码减 1),得到 1000
      • 再求原码(反码除符号位外取反),得到 1111,对应的十进制数是 -7,这显然是错误的结果,是溢出导致的。
减法溢出(可转化为加法)
  • 十进制计算:计算 -4 - 5
  • 二进制转换与计算
    • 原码
      • -4 的原码是 1100
      • -5 的原码是 1101
    • 补码
      • -4 的反码是 1011,补码是 1100
      • -5 的反码是 1010,补码是 1011
    • 补码相加1100 + 1011 = 1 0111(这里产生了进位,4 位无法完整存储结果)。
    • 溢出判断:由于是 4 位二进制,只保留低 4 位,结果为 0111,符号位变成了 0,这表明结果是正数,但两个负数相加结果不应该是正数,所以出现了溢出。
    • 结果转回十进制0111 是正数,正数的补码、反码、原码相同,对应的十进制数是 7,这也是错误的结果,是溢出导致的。

3. 总结

  • 溢出原因:在固定位数的二进制表示中,运算结果超出了该位数所能表示的范围,就会出现溢出。
  • 补码运算优势:计算机使用补码进行运算,能够把减法转化为加法,还能统一处理符号位和数值位,简化了硬件设计。不过,溢出会使计算结果出错,在编程时需要特别留意。

下面给出 Java 代码示例来验证上述计算:

public class FourBitAddition {
    public static int fourBitAddition(int a, int b) {
        // 模拟 4 位二进制范围
        int mask = 0b1111;
        int result = (a + b) & mask;

        // 判断是否溢出
        boolean aSign = (a & 0b1000) != 0;
        boolean bSign = (b & 0b1000) != 0;
        boolean resultSign = (result & 0b1000) != 0;
        if (aSign == bSign && aSign != resultSign) {
            System.out.println("溢出发生!");
        }
        return result;
    }

    public static void main(String[] args) {
        // 示例 1: 7 + 2
        int result1 = fourBitAddition(7, 2);
        System.out.printf("7 + 2 的 4 位二进制结果: %s,十进制: %d%n",
                Integer.toBinaryString(result1), result1);

        // 示例 2: -4 - 5
        int result2 = fourBitAddition(-4, -5);
        System.out.printf("-4 - 5 的 4 位二进制结果: %s,十进制: %d%n",
                Integer.toBinaryString(result2 & 0b1111), result2 & 0b1111);
    }
}    

下面是Java 代码用于模拟 4 位二进制加法并判断溢出情况:
代码解释
1. fourBitAddition方法:
    - mask 变量用于模拟 4 位二进制的范围,通过按位与操作 & 来截取结果的低 4 位。
    - 计算 a、b 和 result 的符号位,通过判断符号位是否满足溢出条件来输出相应信息。
    - 最后返回截取低 4 位后的结果。

2. main方法:
    - 调用 fourBitAddition 方法进行两次示例计算,分别是 7 + 2-4 - 5- 使用 Integer.toBinaryString 方法将结果转换为二进制字符串输出,并同时输出十进制结果。对于负数的情况,使用 & 0b1111 确保输出的是 4 位二进制结果。 

在这个代码里,four_bit_addition 函数模拟了 4 位二进制的加法,并且判断是否有溢出情况。通过示例计算可以看到溢出会使结果出错。

2. 右移运算符(>>)

  • 定义:将二进制位向右移动指定的位数,左侧补符号位(正数补 0,负数补 1)。
  • 示例:
    • 正数:8{10} = 0000 1000{2},右移 2 位后变为 0000 0010(即 2)。
    • 负数:-8{10} = 1111 1000{2},右移 2 位后变为 1111 1110(即 -2)。
  • 数学意义:相当于除以 2n 并向下取整(对负数可能不符合预期)。
  • 注意:右移是“算术右移”,符号位保持不变。

3. 无符号右移运算符(>>>)

  • 定义:将二进制位向右移动指定的位数,左侧补零(忽略符号位)。
  • 示例:
    • 负数:-8{10} = 1111 1000,无符号右移 2 位后变为 0011 1110(即 62)。
  • 适用场景:处理二进制数据(如网络协议中的字节序转换)。
  • 注意:
    • 仅在部分语言中支持(如 Java、JavaScript)。
    • C/C++ 中没有无符号右移,右移行为取决于操作数是否为无符号类型。

不同语言的差异

语言左移(<<)右移(>>)无符号右移(>>>)
Java一致算术右移支持
C/C++一致算术右移(取决于类型)不支持(无符号右移用 >>
JavaScript一致算术右移支持
Python一致算术右移无符号右移需自定义
MySQL一致算术右移(整数)无符号右移需使用 UNSIGNED 类型

实际应用

  • 快速计算:左移代替乘法(如 a << 3 等价于 a * 8)。
  • 位掩码操作:通过移位提取或设置特定位。
  • 处理二进制数据:网络字节序转换(如大端转小端)。

常见误区

  • 右移与除法的区别:
    右移对负数的处理可能与数学除法不同。例如:
    -7 >> 1 = -4(右移向下取整),而 -7 / 2 = -3(数学除法向零取整)。
    
  • 溢出问题:左移可能导致数值超出类型范围(如 int 溢出为负数)。

如果需要进一步的例子或语言特定的细节,可以随时告诉我! 😊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

点滴汇聚江河

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

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

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

打赏作者

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

抵扣说明:

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

余额充值