当前位置: 首页 > news >正文

第十七天:原码、反码、补码与位运算

原码、反码、补码与位运算

一、原码、反码、补码

1、原码

  • 定义:原码是一种简单的机器数表示法。对于一个有符号整数,最高位为符号位, 0 表示正数, 1 表示负数,其余位表示数值的绝对值。
  • 示例:以 8 位二进制为例, +5 的原码是 00000101 , -5 的原码是 10000101 。
  • 问题:原码在进行加减法运算时比较复杂,因为要根据符号位判断是加法还是减法,并且对于 0 有两种表示形式( +0 : 00000000 , -0 : 10000000 ),这给计算机处理带来不便。

2、反码

  • 定义:正数的反码与原码相同;负数的反码是在原码的基础上,符号位不变,其余各位取反。
  • 示例:还是以 8 位二进制为例, +5 的反码是 00000101 , -5 的原码是 10000101 ,其反码则为 11111010 。
  • 作用:反码主要是作为从原码到补码的过渡。虽然它解决了 0 的表示不唯一问题( +0 和 -0 的反码都是 00000000 ),但在加减法运算上仍不够理想。

3、补码

  • 定义:正数的补码与原码相同;负数的补码是在反码的基础上,末位加 1 。

  • 示例:同样 8 位二进制, +5 的补码是 00000101 , -5 的反码是 11111010 ,其补码则为 11111011 。

  • 优势:补码在计算机中得到广泛应用,它解决了原码和反码在运算上的不足。在补码系统中, 0 只有一种表示形式( 00000000 )。而且使用补码进行加减法运算时,不需要额外判断符号位,可以直接将符号位和数值位一起参与运算,简化了运算规则,提高了运算效率。例如,计算 5 + (-3) , 5 的补码是 00000101 , -3 的补码是 11111101 ,两者相加:

    00000101

  • 11111101

100000010

由于是 8 位二进制,最高位的 1 溢出被舍弃,结果为 00000010 ,即 2 ,运算结果正确。

  • 原码是最直观的有符号数表示方法,但运算复杂且 0 的表示不唯一。
  • 反码是从原码到补码的过渡,一定程度上解决了 0 的表示问题,但运算仍不够简便。
  • 补码克服了原码和反码的缺点,成为计算机中表示有符号整数的标准方式,极大地简化了运算逻辑,提高了计算机处理有符号整数运算的效率。

二、位运算

1. 位与( & )

  • 运算规则:对两个整数的二进制表示中每一位进行比较,只有当两个对应位都为 1 时,结果位才为 1 ,否则为 0 。
  • 示例代码:
 
#include <iostream>int main() {int num1 = 10; // 二进制: 1010int num2 = 6;  // 二进制: 0110int result = num1 & num2;std::cout << num1 << " & " << num2 << " = " << result << std::endl;// 计算过程://  1010// & 0110// ------//  0010  结果为2return 0;
}
  • 应用场景:
  • 掩码操作:通过与一个特定的掩码值进行位与操作,可以提取或保留某些位。例如,要获取一个字节(8位)的低4位,可以与掩码 0x0F (二进制 00001111 )进行位与操作。
  • 判断奇偶性:与 1 进行位与操作,如果结果为 1 ,则该数为奇数;如果结果为 0 ,则为偶数。因为奇数的二进制最低位是 1 ,偶数的二进制最低位是 0 。

2. 位或( | )

  • 运算规则:对两个整数的二进制表示中每一位进行比较,只要两个对应位中有一个为 1 ,结果位就为 1 ,只有当两个对应位都为 0 时,结果位才为 0 。
  • 示例代码:
#include <iostream>int main() {int num1 = 10; // 二进制: 1010int num2 = 6;  // 二进制: 0110int result = num1 | num2;std::cout << num1 << " | " << num2 << " = " << result << std::endl;// 计算过程://  1010// | 0110// ------//  1110  结果为14return 0;
}

应用场景:

  • 设置标志位:如果要将一个整数的某些位设置为 1 ,可以与一个相应位为 1 的掩码进行位或操作。例如,要将一个整数的第3位和第5位设置为 1 ,可以与掩码 0x28 (二进制 00101000 )进行位或操作。
  • 合并数据:在处理一些标志集合时,可以通过位或操作将不同的标志合并到一个整数中。

3. 异或( ^ )

  • 运算规则:对两个整数的二进制表示中每一位进行比较,当两个对应位不同时,结果位为 1 ,当两个对应位相同时,结果位为 0 。
  • 示例代码:
#include <iostream>int main() {int num1 = 10; // 二进制: 1010int num2 = 6;  // 二进制: 0110int result = num1 ^ num2;std::cout << num1 << " ^ " << num2 << " = " << result << std::endl;// 计算过程://  1010// ^ 0110// ------//  1100  结果为12return 0;
}

应用场景:

  • 数据加密与解密:简单的异或加密算法中,通过将数据与一个密钥进行异或操作来加密数据,解密时再次与相同的密钥异或即可还原数据。
  • 交换两个数:不使用临时变量交换两个整数的值。例如:
#include <iostream>int main() {int a = 5;int b = 7;a = a ^ b;b = a ^ b;a = a ^ b;std::cout << "a = " << a << ", b = " << b << std::endl;return 0;
}
  • 利用了异或操作的特性, a ^ b ^ b 等于 a , a ^ b ^ a 等于 b ,从而实现了两个数的交换。

4. 按位取反( ~ )

  • 运算规则:对一个整数的二进制表示中的每一位进行取反操作,即将 0 变为 1 , 1 变为 0 。
  • 示例代码:
#include <iostream>int main() {int num = 5; // 二进制: 0000 0101int result = ~num;std::cout << "~" << num << " = " << result << std::endl; // 计算过程:// 原: 0000 0101// 取反: 1111 1010 // 在有符号整数中,这是 -6 的补码表示return 0;
}

应用场景:

  • 创建掩码:通过对特定值进行按位取反可以生成用于位操作的掩码。例如,要创建一个除了第 3 位为 0 其余位都为 1 的掩码,可以对 1 << 3 (即 0000 1000 )进行按位取反,得到 1111 0111 。
  • 在特定算法中反转位模式:某些加密算法或数据处理算法中可能需要对数据的位模式进行反转。

5. 左移( << )

  • 运算规则:将一个整数的二进制表示向左移动指定的位数,右边空出的位用 0 填充。每左移一位,相当于该数乘以 2 (在不溢出的情况下)。
  • 示例代码:
#include <iostream>int main() {int num = 5; // 二进制: 0000 0101int result = num << 2;std::cout << num << " << 2 = " << result << std::endl; // 计算过程:// 原: 0000 0101// 左移2位: 0001 0100  结果为20return 0;
}

应用场景:

  • 快速乘法:当需要将一个数乘以 2 的幂次方时,使用左移操作比乘法操作更高效。例如, a * 8 可以写成 a << 3 ,因为 8 = 2^3 。
  • 设置标志位:通过左移操作可以将 1 移动到特定位置来设置标志位。例如, 1 << 5 得到 0010 0000 ,可用于设置第 5 位的标志。

6. 右移( >> )

  • 运算规则:将一个整数的二进制表示向右移动指定的位数。对于无符号整数,左边空出的位用 0 填充;对于有符号整数,如果原数为正数,左边空出的位用 0 填充,如果原数为负数,左边空出的位用符号位(即最高位)填充,这称为算术右移。每右移一位,相当于该数除以 2 (向下取整)。
  • 示例代码(无符号整数):
#include <iostream>int main() {unsigned int num = 20; // 二进制: 0001 0100unsigned int result = num >> 2;std::cout << num << " >> 2 = " << result << std::endl; // 计算过程:// 原: 0001 0100// 右移2位: 0000 0101  结果为5return 0;
}
  • 示例代码(有符号整数):
#include <iostream>int main() {int num = -20; // 二进制补码: 1110 1100int result = num >> 2;std::cout << num << " >> 2 = " << result << std::endl; // 计算过程:// 原: 1110 1100// 右移2位: 1111 1011  结果为 -5return 0;
}

应用场景:

  • 快速除法:当需要将一个数除以 2 的幂次方时,使用右移操作比除法操作更高效。例如, a / 4 可以写成 a >> 2 ,因为 4 = 2^2 。
  • 提取特定部分:可以通过右移操作将需要的位移动到最低位,然后通过与操作提取。例如,要获取一个整数二进制表示的低 4 位,可以先右移 n 位( n 为需要丢弃的高位数),然后与 0x0F 进行与操作。
http://www.dtcms.com/a/315773.html

相关文章:

  • RAFT:让语言模型更聪明地用文档答题
  • Java从入门到精通 - 集合框架(一)
  • 最长连续序列(每天刷力扣hot100系列)
  • FastDeploy2.0:报qwen2.embed_tokens.weight
  • 2.4 组件通信
  • 24. 前端-js框架-Vue
  • Occ3D: A Large-Scale 3D Occupancy Prediction Benchmark for Autonomous Driving
  • Python高级编程与实践:Python性能分析与优化
  • Java技术栈/面试题合集(3)-Java并发篇
  • 【功能测试】软件功能上线测试经验总结
  • 场外个股期权的额度为何受限?
  • java web 服务员点餐系统demo 比较完整的前端后端+mysql + 图片上传 练习
  • 从审批流到审计链:刻录系统的全周期管控技术解析
  • Spring MVC框架中DispatcherServlet详解
  • 【开源工具】基于Python的PDF清晰度增强工具全解析(附完整源码)
  • LeetCode算法日记 - Day 2: 快乐数、盛水最多容器
  • 力扣经典算法篇-43-全排列(经典回溯问题)
  • vite面试题及详细答案120题(01-30)
  • 普通树状数组
  • 《Node.js与 Elasticsearch的全文搜索架构解析》
  • Leetcode 13 java
  • 2025-08-05Gitee + PicGo + Typora搭建免费图床
  • MongoDB学习专题(二)核心操作
  • MongoDB 从3.4.0升级到4.0.0完整指南实战-优雅草蜻蜓I即时通讯水银版成功升级-卓伊凡|bigniu
  • 时序数据库flux aggregateWindow命令详解
  • Baumer相机如何通过YoloV8深度学习模型实现道路场所路人口罩的检测识别(C#代码UI界面版)
  • 概率论之条件概率
  • ubuntu自动重启BUG排查指南
  • C++ - 仿 RabbitMQ 实现消息队列--服务端核心模块实现(六)
  • Go 单元测试:如何只运行某个测试函数(精确控制)