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

【计算机科学】位运算:揭开二进制世界的奥秘

位运算是计算机运算的一种基础操作,直接作用于数据的二进制位(bit),在计算机中具有极高的效率。无论是编写高效算法,还是进行底层开发,位运算都扮演着重要角色。本文将从位运算的起源、常见操作符、应用场景到一些实际开发中的使用技巧,带你系统性地了解位运算,并通过代码示例让你轻松掌握。


目录

  1. 位运算的来源与基本概念
  2. 常见位运算符与含义
  3. 位运算的应用实例
  4. 实际开发中的位运算技巧
  5. 总结

1. 位运算的来源与基本概念

位运算在计算机科学中是非常基础的操作,它直接作用于二进制数据的每个位。为了理解位运算,我们需要了解计算机如何存储和处理数据,以及它在底层是如何利用二进制实现高效操作的。

位运算的起源

计算机中,数据以二进制形式表示,即每一位(bit)可以是01,这正好对应电路中的“关”和“开”两种状态。这种数字逻辑电路控制构成了计算机的基础,使得位运算成为最基础的运算形式之一。

位运算起源于逻辑电路的概念,在物理层面上,逻辑门(如“与”“或”“非”门)就是通过处理电压高低来代表01。二进制位通过一系列运算符的组合,能够实现复杂的数据计算和处理。例如,加法、乘法等操作都可以通过二进制的位运算来实现。在底层,所有高级语言中的数值运算最终都会转换成硬件指令,这些指令直接在硬件层上进行位运算,从而保证高效的执行速度。

为什么使用位运算?

位运算的优点包括:

  1. 高效性
    位运算的执行速度非常快,因为计算机的CPU原生支持位操作,且操作直接在二进制位上进行。相比加减乘除,位运算可以在底层减少指令数,提升运行速度。很多高级程序中使用位运算来替代复杂计算,以提高程序效率。

  2. 节省内存
    位运算可以压缩数据,节省存储空间。例如,使用标志位可以在一个整数的二进制位表示多个布尔状态(如8个标志位),避免使用多个变量,从而减少内存消耗。这在嵌入式系统中尤其重要。

  3. 逻辑控制简单
    位运算可以直接操作二进制位,使得某些操作变得简单直观。例如,通过位运算可以轻松地设置、清除或检查某些位的状态,不必使用循环或条件语句进行复杂判断。


2. 常见位运算符与含义

运算符名称描述示例(假设 a = 5b = 3
&按位与两个二进制数的每个对应位都为1时,结果的该位为1,否则为0
应用:常用于掩码操作,例如保留数的某些特定位。
a & b = 1
``按位或两个二进制数的每个对应位只要有一个为1,结果的该位就为1
应用:用于组合多个标志位,或设置某些位为1
^按位异或两个二进制数的对应位不同则为1,相同则为0
应用:用于位翻转和交换两个变量的值,或实现简单加密。
a ^ b = 6
~按位取反将数的每个二进制位翻转,0110。这种操作等价于取负数减一。
应用:快速生成负数,或取反所有位。
~a = -6
<<左移将数的二进制位向左移动指定的位数,右侧补0,相当于乘以2^n
应用:快速计算乘法或扩大值范围。
a << 1 = 10
>>右移将数的二进制位向右移动指定的位数,左侧补符号位。等效于除以2^n
应用:快速计算除法,缩小值范围或分段数值。
a >> 1 = 2

示例与解释

  1. 按位与 &

    • 作用:常用于掩码操作,即提取数值中的特定位。例如,判断一个数是否是奇数,我们可以检查其最低位是否为1。
    • 示例if (a & 1) == 1 判断a是否为奇数,1的二进制位 0001a 的最低位相与,若为奇数,结果即为1
  2. 按位或 |

  • 作用:将多个“标志位”合并为一个数值。按位或操作会把每个位中的“1”保留下来,所以只要有一方的该位为1,结果的该位也会是1
  • 示例:假设一个用户权限系统中,用位运算代表用户的不同权限:READ权限是 0001WRITE权限是 0010。我们可以通过 READ | WRITE 来将这两个权限合并到一起,表示该用户既有读取权限,又有写入权限。
    READ = 0b0001       # 二进制:0001
    WRITE = 0b0010      # 二进制:0010
    permissions = READ | WRITE  # 结果为 0011 表示读写权限都有
    
  1. 按位异或 ^
  • 作用:当两个数的某个位不同时,按位异或会把该位设为1。否则,该位设为0。它的常用场景是交换两个变量的值,不需要使用临时变量。
  • 示例:如果我们想交换变量 ab 的值,可以使用以下代码:
    a = 5   # 二进制:0101
    b = 3   # 二进制:0011a = a ^ b   # a 变为 6(0110)
    b = a ^ b   # b 变为 5(0101,即 a 的初始值)
    a = a ^ b   # a 变为 3(0011,即 b 的初始值)
    
    经过这三步,ab 的值已经互换。这种方法常用于低级优化。

  1. 按位取反 ~
  • 作用:按位取反会将一个数的每个位都变成相反的状态,0变成11变成0
  • 示例:对于整数 5(在二进制中为 0000 0101),使用按位取反后会得到1111 1010,这个二进制数在有符号数中表示-6
    x = 5         # 二进制:0000 0101
    result = ~x   # 结果是 -6
    
    这种取反运算在位运算中可以快速生成负数的补码表示。
  1. 左移 <<

    • 作用:在位运算中,左移相当于乘2的幂。例如,将3 << 2等同于3 * 4
    • 示例3 << 1的结果是6
  2. 右移 >>

    • 作用:右移相当于将数缩小一半,适用于快速除法。
    • 示例10 >> 1 结果为5

3. 位运算的应用实例

位运算的高效性和紧凑性使其在实际开发中广泛应用于权限管理、加密解密、数据压缩、掩码操作等领域。下面是一些典型的应用场景和实例:

1. 权限管理

在权限系统中,每个权限位都可以用二进制的一个位来表示,多个权限就可以组合在一个整数中。这样做可以减少存储空间,并且方便检查、赋予或删除特定权限。

示例:权限设置和检查

假设有以下三种权限:

  • READ 权限:二进制为 001
  • WRITE 权限:二进制为 010
  • EXECUTE 权限:二进制为 100

将这三种权限组合使用位运算管理:

# 定义权限
READ = 0b001       # 读权限
WRITE = 0b010      # 写权限
EXECUTE = 0b100    # 执行权限# 组合权限
user_permissions = READ | WRITE  # 用户拥有读和写权限# 检查权限
has_read = (user_permissions & READ) != 0      # 是否有读权限
has_execute = (user_permissions & EXECUTE) != 0  # 是否有执行权限
print(f"Read: {has_read}, Execute: {has_execute}")# 添加权限
user_permissions |= EXECUTE  # 增加执行权限

通过这种方式,可以快速组合、检查或移除权限,提高权限管理的效率和代码的清晰度。

2. 加密与解密

在数据加密中,异或(XOR)操作可以用于实现简单的加密和解密。异或的特性是:a ^ b ^ b = a,即如果将某个值与密钥key进行一次异或操作可以加密,再次用同一个密钥异或可以解密回来。

示例:简单加密解密

假设我们有一个数 data 需要加密和解密:

data = 123        # 原始数据
key = 25          # 加密密钥# 加密
encrypted_data = data ^ key
print(f"Encrypted: {encrypted_data}")# 解密
decrypted_data = encrypted_data ^ key
print(f"Decrypted: {decrypted_data}")

在这个例子中,通过将 datakey 进行异或,生成了加密后的数据。再次用同样的 key 进行异或操作,就可以还原为原始数据。这种方法虽简单但不适用于高强度加密场景,适合用于简单的数据隐藏。

3. 使用掩码操作提取特定位

掩码操作可以帮助我们提取特定的二进制位,用于状态检查或分离数据。掩码通常是一个指定的二进制数,通过与原数据按位与 & 操作,可以获取特定位置上的值。

示例:提取某些位的值

假设我们有一个8位二进制数 number = 0b10101100,现在想提取其中的第3位到第5位的值。

number = 0b10101100
mask = 0b00111000  # 掩码,提取第3位到第5位result = (number & mask) >> 3  # 提取并右移3位
print(f"Extracted bits: {bin(result)}")

在这个例子中,通过 & 操作,我们将不需要的位清零,之后右移可以得到所需位的值。在嵌入式开发或低级系统编程中,掩码操作常用于读取特定的硬件状态位。

4. 数据压缩与解压

位操作也能用来压缩信息,将多个标志位或小数据段放入一个数值中。在资源受限的系统中,可以用这种方法节省内存空间。

示例:将多个布尔标志合并为一个字节

假设我们有四个标志 a, b, c, d,每个标志都占用一位,我们可以将它们压缩到一个字节中。

# 四个布尔标志
a, b, c, d = 1, 0, 1, 1# 压缩为一个字节
byte = (a << 3) | (b << 2) | (c << 1) | d
print(f"Compressed byte: {bin(byte)}")# 解压还原各标志位
a_extracted = (byte >> 3) & 1
b_extracted = (byte >> 2) & 1
c_extracted = (byte >> 1) & 1
d_extracted = byte & 1
print(f"Extracted flags: a={a_extracted}, b={b_extracted}, c={c_extracted}, d={d_extracted}")

在这个例子中,我们用位移操作将每个标志位放入一个字节中的不同位置,这样只需要一个字节就能存储多个布尔值。通过位移和按位与可以还原每个标志的值。

5. 位标记处理

在某些游戏开发和状态管理中,位标记是一种常用方式,用于表示对象的不同状态。例如,一个游戏角色的状态可能包括“跳跃中”“攻击中”“受伤中”等多个状态。我们可以用位运算来记录和管理这些状态。

示例:多状态管理

假设我们有以下状态:

  • IS_JUMPING:二进制位 0001
  • IS_ATTACKING:二进制位 0010
  • IS_HURT:二进制位 0100

通过位标记,我们可以组合多个状态,并随时检查或移除某个状态。

# 定义状态位
IS_JUMPING = 0b0001
IS_ATTACKING = 0b0010
IS_HURT = 0b0100# 初始化状态
character_state = 0# 设置状态
character_state |= IS_JUMPING  # 角色跳跃中
character_state |= IS_HURT     # 角色受伤中# 检查状态
is_jumping = (character_state & IS_JUMPING) != 0
is_attacking = (character_state & IS_ATTACKING) != 0
print(f"Jumping: {is_jumping}, Attacking: {is_attacking}")# 移除状态
character_state &= ~IS_HURT  # 角色恢复,不再受伤

在这个示例中,通过按位或来设置状态,按位与检测状态,按位与和按位取反组合则可以移除状态。位标记方式能够在单个整数中存储多个状态,提升状态管理的效率。


这些示例展示了位运算在实际开发中的一些经典应用。通过灵活使用位运算,开发者可以实现更高效的权限管理、数据加密、状态管理等功能,提高程序性能和内存利用率。


4. 实际开发中的位运算技巧

常用的位运算技巧

  1. 判断奇偶性x & 1 可以判断一个数的奇偶性。
  2. 快速乘法和除法:用左移(乘2的幂)和右移(除2的幂)进行高效计算。
  3. 交换变量:使用x = x ^ y交换两个变量。

5. 总结

位运算是编程中既基础又高效的操作工具,因其直接作用于二进制位,使其在性能优化、内存节省和数据处理上拥有显著优势。通过掌握位运算,不仅能够帮助我们在代码中实现更高效的逻辑控制和数据处理,也可以轻松处理权限、加密、状态管理等应用场景。希望本文为你提供了深入的理解和实用的技巧!

相关文章:

【计算机科学】位运算:揭开二进制世界的奥秘

位运算是计算机运算的一种基础操作&#xff0c;直接作用于数据的二进制位&#xff08;bit&#xff09;&#xff0c;在计算机中具有极高的效率。无论是编写高效算法&#xff0c;还是进行底层开发&#xff0c;位运算都扮演着重要角色。本文将从位运算的起源、常见操作符、应用场景…...

弹性裸金属服务器和传统裸金属服务器有什么区别?

弹性裸金属服务器是一种结合了传统裸金属服务器和云计算资源两种特点的服务器&#xff0c;是一种云计算服务&#xff0c;下面我们就来了解一下弹性裸金属服务器和传统裸金属服务器之间有什么区别吧&#xff01; 弹性裸金属服务器能够支持企业快速部署新的硬件和软件系统&#x…...

shodan(五)连接Mongodb数据库Jenkinsorg、net、查看waf命令

声明&#xff1a;学习素材来自b站up【泷羽Sec】&#xff0c;侵删&#xff0c;若阅读过程中有相关方面的不足&#xff0c;还请指正&#xff0c;本文只做相关技术分享,切莫从事违法等相关行为&#xff0c;本人一律不承担一切后果 引言&#xff1a; 1.Shodan 是一个专门用于搜索连…...

ThingsBoard规则链节点:Push to Edge节点详解

引言 1. Push to Edge 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 边缘计算 3.2 本地数据处理 3.3 实时响应 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0c;提供了设备管…...

基于 EventBridge + DashVector 打造 RAG 全链路动态语义检索能力

作者&#xff1a;肯梦 本文将演示如何使用事件总线&#xff08;EventBridge&#xff09;&#xff0c;向量检索服务&#xff08;DashVector&#xff09;&#xff0c;函数计算&#xff08;FunctionCompute&#xff09;结合灵积模型服务 [ 1] 上的 Embedding API [ 2] &#xff0…...

【golang/navmesh】使用recast navigation进行寻路

目录 说在前面安装使用可视化 说在前面 go version&#xff1a;1.20.2 linux/amd64操作系统&#xff1a;wsl2detour-go版本&#xff1a;v0.2.0github&#xff1a;这里&#xff0c;求star! 安装 使用go mod安装即可go get github.com/o0olele/detour-go使用 使用场景模型构建n…...

【软考】Redis不同的数据类型和应用场景。

Redis的不同数据类型和对应的应用场景&#xff1a; Redis 数据类型及其应用场景 String&#xff08;字符串&#xff09; 特点&#xff1a;简单的值存储&#xff0c;支持二进制数据。应用场景&#xff1a; 缓存用户会话。缓存小的配置文件。缓存计数器。文章浏览量&#xff0…...

java 对人名和电话 脱敏-replaceAll

学习了《正则匹配人名》和《正则匹配电话号码》&#xff0c;如果要一起进行脱敏处理&#xff0c;改怎么做&#xff1f; 脱敏的&#xff0c;考虑配置规则&#xff0c;进行匹配的方式进行处理&#xff1a; 脱敏规则&#xff1a; DesensitizationRules Data public class Desens…...

计算机网络:网络层 —— 网络地址转换 NAT

文章目录 网络地址转换 NAT 概述最基本的 NAT 方法NAT 转换表的作用 网络地址与端口号转换 NAPTNAT 和 NAPT 的缺陷 网络地址转换 NAT 概述 尽管因特网采用了无分类编址方法来减缓 IPv4 地址空间耗尽的速度&#xff0c;但由于因特网用户数量的急剧增长&#xff0c;特别是大量小…...

【Pikachu靶场:XSS系列】xss之过滤,xss之htmlspecialchars,xss之herf输出,xss之js输出通关啦

一、xss之过滤 <svg onloadalert("过关啦")> 二、xss之htmlspecialchars javascript:alert(123) 原理&#xff1a;输入测试文本为herf的属性值和内容值&#xff0c;所以转换思路直接变为js代码OK了 三、xss之href输出 JavaScript:alert(假客套) 原理&#x…...

面向制造和装配的产品设计指南(二):面向装配的设计指南

参考引用 面向制造和装配的产品设计指南 1. 概述 1.1 装配的概念 装配是指把多个零件组装成产品&#xff0c;使得产品能够实现相应的功能并体现产品的质量&#xff0c;装配包含三层含义 把零件组装在一起实现相应的功能体现产品的质量 1.2 最好和最差的装配工序 1.3 面向装…...

Python中的PDF处理工具:PyPDF2和ReportLab使用指南

Python中的PDF处理工具&#xff1a;PyPDF2和ReportLab使用指南 在日常工作和项目中&#xff0c;PDF 文件处理是个常见需求&#xff0c;不论是合并报告、加密文档、填充表单&#xff0c;还是生成发票。Python 中有许多用于操作 PDF 文件的库&#xff0c;其中 PyPDF2 和 ReportL…...

【vxe-table】多选筛选项对列表的列进行动态的显示与隐藏

需求&#xff1a; 列表的组成部分由&#xff1a;一些固定的列&#xff0c;如:姓名&#xff0c;工号&#xff0c;以及 需要动态显示与隐藏的列&#xff0c;如&#xff1a;出勤、旷工、事假、病假等假勤类型 1、通过多选框多选&#xff0c;展示选中的列&#xff0c;未选中的不展示…...

微信小程序uniapp+vue飞机订票航空售票系统

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 对于小程序飞机订票信息管理所牵扯的信息管理及数据保存都是非常多的&#xff0c;举例像所有的管理员&#xff1b;管理员…...

如何取消Outlook中的循环会议

如何取消Outlook中的循环会议 参考链接&#xff1a;https://iknow.lenovo.com.cn/detail/195430 1、打开Outlook&#xff0c;进入 日历 视图界面&#xff1b; 2、 选择并双击要取消的循环会议&#xff1b; 3、 在 打开定期项目 对话框中选择整个序列&#xff0c;然后单击 确…...

Docker-- cgroups资源控制实战

上一篇&#xff1a;容器化和虚拟化 什么是cgroups&#xff1f; cgroups是Linux内核中的一项功能&#xff0c;最初由Google的工程师提出&#xff0c;后来被整合进Linux内核; 它允许用户将一系列系统任务及其子任务整合或分隔到按资源划分等级的不同组内&#xff0c;从而为系统…...

使用Python和Vosk库实现语音识别

使用Python和Vosk库实现语音识别 在人工智能和机器学习领域&#xff0c;语音识别技术正变得越来越重要。Python作为一种强大的编程语言&#xff0c;拥有丰富的库和框架&#xff0c;可以方便地实现语音识别功能。今天&#xff0c;我们将介绍如何使用Python中的SpeechRecognitio…...

stm32使用串口的轮询模式,实现数据的收发

------内容以b站博主keysking为原型&#xff0c;整理而来&#xff0c;用作个人学习记录。 首先在STM32CubeMX中配置 前期工作省略&#xff0c;只讲重点设置。 这里我配置的是USART2的模式。 会发现&#xff0c;PA2和PA3分别是TX与RX&#xff0c;在连接串口时需要TX对RX&…...

105. UE5 GAS RPG 搭建主菜单

在这一篇&#xff0c;我们将实现对打开游戏显示的主菜单进行搭建&#xff0c;主菜单将显示游戏主角&#xff0c;游戏名称和进入游戏和退出游戏两个按钮。 搭建菜单场景 我们将主菜单设置为一个单独的场景&#xff0c;前面可以显示对应的UI控件&#xff0c;用于玩家操作&#…...

基于 JAVASSM(Java + Spring + Spring MVC + MyBatis)框架开发一个医院挂号系统

基于 JAVASSM&#xff08;Java Spring Spring MVC MyBatis&#xff09;框架开发一个医院挂号系统是一个实用的项目。 步骤一&#xff1a;需求分析 明确系统需要实现的功能&#xff0c;比如&#xff1a; 用户注册和登录查看医生列表预约挂号查看预约记录取消预约管理员管…...

Golang | Leetcode Golang题解之第540题有序数组中的单一元素

题目&#xff1a; 题解&#xff1a; func singleNonDuplicate(nums []int) int {low, high : 0, len(nums)-1for low < high {mid : low (high-low)/2mid - mid & 1if nums[mid] nums[mid1] {low mid 2} else {high mid}}return nums[low] }...

影刀RPA实战:嵌入python,如虎添翼

1. 影刀RPA与Python的关系 影刀RPA与Python的关系可以从以下几个方面来理解&#xff1a; 技术互补&#xff1a;影刀RPA是一种自动化工具&#xff0c;它允许用户通过图形化界面创建自动化流程&#xff0c;而Python是一种编程语言&#xff0c;常用于编写自动化脚本。影刀RPA可以…...

es 数据清理delete_by_query

POST /索引名/_delete_by_query?conflictsproceed&scroll_size2000&wait_for_completionfalse&slices36 {"size": 2000, "query": {"bool": { "must": [{"terms": {"rule_id": [800007]}}]}} }slice…...

【每日 C/C++ 问题】

一、C 中类的三大特性是什么&#xff1f;请简要解释。 封装、继承、多态 封装&#xff1a;将事物的属性&#xff08;成员变量&#xff09;和行为&#xff08;成员函数&#xff09;封装在一起形成一个类。并且可以设置相应的访问权限&#xff08;私有的 受保护的 公有的&#…...

stm32学习4

学习目录 一.流水灯1.创建文件2.编写相关代码 一.流水灯 1.创建文件 将方法进行分类保存在不同的 .c 文件中&#xff0c;方便复用和寻找&#xff1b; 创建Hardware\LED文件&#xff0c;其中有led.c和led.h文件&#xff0c;用于存放有关LED灯操作的方法&#xff1b; 在User文…...

Midjourney国内直登

Midjourney确实是一个强大的AI绘画工具&#xff0c;能够根据用户输入的文本生成高质量的图像。然而&#xff0c;由于国内的网络限制&#xff0c;直接访问Midjourney可能会遇到障碍。 目前&#xff0c;已经有一些国内代理或中转平台可以帮助用户更方便地使用Midjourney&#xf…...

【双目视觉标定】——3面结构光相机标定实践(获取相机内参)~未完待续

相机标定基本原理及双目相机内参解析 相机标定是计算机视觉中的一个重要步骤&#xff0c;旨在确定相机的内部和外部参数&#xff0c;以便在图像处理中进行准确的三维重建、物体识别等任务。本文将重点讲解双目相机的内参和外参原理&#xff0c;并结合实际参数进行分析。 一、…...

Python常用脚本集锦

收集了一些常用Python脚本&#xff0c;作为平时练手使用&#xff0c;也可以作为自己的笔记&#xff0c;用到哪个功能可以自己查询一下即可。 文件和目录管理 复制文件 import shutil# 复制源文件到目标文件 shutil.copy(source.txt, destination.txt)移动文件 import shuti…...

MacBook 如何设置打开json格式文件的默认程序是vs code

首先右键选中文件&#xff0c;然后选中显示简介 然后选中打开方式 设置成vs code...

如何在 Spring Boot 中实现多数据源的事务管理?

在 Spring Boot 中实现多数据源的事务管理可以通过以下几种方式&#xff1a; 一、使用编程式事务管理 配置多个数据源 如同前面提到的&#xff0c;在 application.properties 或 application.yml 文件中配置多个数据源的连接信息&#xff0c;并创建对应的数据源 bean。 手动开启…...