计算机常见运算之左移操作、右移操作以及按位与、按位或

news2024/9/22 21:35:10

文章目录

  • 前言
  • 一、左移操作(<<)和 右移操作(>>)
    • 1.1 左移操作(<<)
    • 1.2 右移操作(>>)
    • 1.3 应用场景
  • 二、按位与 (&) 和 按位或 (|)
    • 2.1 按位与 (&)
    • 2.2 按位或 (|)
    • 2.3 按位操作的实际应用
  • 三、应用案例
    • 3.1 应用案例代码
    • 3.2 应用案例分析


前言

本文主要探讨计算机中一些常见的运算,比如左移操作(<<)、右移操作(>>),按位与 (&) 、按位或 (|),最后通过一个例子结合按位与和右移操作实现获取一个字节中所有位的功能。


一、左移操作(<<)和 右移操作(>>)

左移和右移是计算机编程中常用的位操作,它们用于将数值的二进制位向左或向右移动,从而改变数值的大小。理解这些操作对处理低级别数据、优化代码性能以及执行特定算法(如加密和解密)都是非常有用的。

1.1 左移操作(<<)

左移操作符 << 会将一个数的所有二进制位向左移动指定的位数。右侧空出的位用 0 填充。左移操作实际上相当于乘以 2 的幂。

uint8_t a = 0b00001111; // 二进制表示,十进制 15
a = a << 2;

初始值:a = 0b00001111 (二进制 15)
执行 a << 2 后,a = 0b00111100 (二进制 60

在这个例子中,a 的所有位向左移动了两位。从十进制的角度来看,左移两位相当于 15 * 2^2 = 60。即原来是15,左移两位后变成60。

数学意义:

从十进制的角度来看,左移 n 位,相当于乘以 2^n。例如:

x << 1 等同于 x * 2^1
x << 2 等同于 x * 2^2

以此类推…

这种位操作是非常高效的,因为在硬件层面上,位移操作比乘法更快。

1.2 右移操作(>>)

右移操作符 >> 会将一个数的所有二进制位向右移动指定的位数。左侧空出的位根据操作数是有符号的还是无符号的,以及编译器的实现,可能会填充 0 或符号位(即符号扩展)。

uint8_t b = 0b11000000; // 二进制表示,十进制 192
b = b >> 2;

初始值:b = 0b11000000 (二进制 192)
执行 b >> 2 后,b = 0b00110000 (二进制 48

在这个例子中,b 的所有位向右移动了两位。从十进制的角度来看,右移两位相当于192 ÷ 2^2 = 48。即原来是192,右移两位后变成48。

数学意义:
从十进制的角度来看,右移 n 位,相当于除以 2^n。例如:

x >> 1 等同于 x ÷ 2^1
x >> 2 等同于 x ÷ 2^2

以此类推…

但是要注意,右移操作会截断数值。例如,5 >> 1 的结果是 2,而不是 2.5。

特别注意:

1. 无符号数和有符号数的区别:

  • 对于无符号数,右移时左侧填充 0。
  • 对于有符号数(如 int 类型的负数),右移时可能会进行符号扩展,即用原符号位填充左侧。例如,-2 的二进制为 11111110(假设 8 位),右移一位可能会变成 11111111(保持负数)。

2. 超出范围的移位:

  • 如果移位的位数超过了数据类型的位数(例如,uint8_t 只有 8位),移位的结果是未定义的(依赖于具体的编译器实现),因此一般要确保移位数小于类型的位宽。

1.3 应用场景

场景描述
快速乘除法左移和右移操作被广泛用于实现快速乘法和除法
位掩码操作用于生成特定位的掩码,特别是在嵌入式系统中,常用来控制硬件
数据编码和解码例如压缩算法、加密算法中需要处理位级数据
循环移位一些应用中需要通过移位操作来实现循环移位,例如哈希函数的实现

二、按位与 (&) 和 按位或 (|)

位操作(如按位与和按位或)是一种在计算机系统中非常常见的运算,用于直接操作整数的二进制位。它们的工作原理是基于每个位的值,而不是对整个数字进行通常的数学运算,这对于底层硬件控制操作特别有用,因为硬件通常是通过具体的位进行控制的。

2.1 按位与 (&)

逻辑与的规则是:只要有一个位为 0,结果就为 0。只有在两个位都为 1 时,结果才为 1简而言之就是:有假为假,全真为真

位1位2结果
000
010
100
111

举例说明:

0b10101010 // 十进制 170 
0b11001100 // 十进制 204
10001000// 十进制 136

170 & 204 = 1360b10101010 & 0b11001100 = 0b10001000 

按位与的逻辑是有假为假,全真为真,具体分析如下:
10101010// 十进制 170 
11001100// 十进制 204
10001000// 十进制 136

使用计算器验证了一下没有问题

在这里插入图片描述

2.2 按位或 (|)

逻辑或的规则是:只要有一个位为 1,结果就为 1。只有在两个位都为 0 时,结果才为 0简而言之就是:有真为真,全假为假。

位1位2结果
000
011
101
111

举例说明:

0b10101010// 十进制 170
0b11001100// 十进制 204
0b11101110// 十进制 238


0b10101010 | 0b11001100 = 0b11101110

按位或的逻辑是有真为真,全假为假,具体分析如下:
10101010// 十进制 170 
11001100// 十进制 204
11101110// 十进制 238


使用计算器验证了一下没有问题

在这里插入图片描述

2.3 按位操作的实际应用

通过按位与和按位或,可以有效地操作数据的特定位,达到如提取、设置、清除和切换等目的。

1. 提取特定位

按位与操作常用于从一个字节或一个数中提取特定的位,以下代码实现了在一个字节中依次提取位的操作(从左(最高位)往右(最低位))

typedef enum {
    Bit_RESET = 0,
    Bit_SET
} BitAction;

void MyI2C_W_SDA(int BitValue) {
    printf("BitValue:%d\n", BitValue);
}

void MyI2C_SendByte(unsigned char Byte) {
    int i;
    for (i = 0; i < 8; i++) {
        // 使用三元运算符将结果转换为 0 或 1
        MyI2C_W_SDA((Byte & (0x80 >> i)) ? Bit_SET : Bit_RESET);
    }
}

首先,按照上面分析可知,若想从一个字节中提取特定的位(不是0就是1),我们可以使用按位与的思想。先从最高位开始,也就是0b10000000,转换成十六进制即0x80,然后我们让0x80依次右移即可。

假设 Byte = 0x75,转换成二进制为0b01110101,那么具体的过程如下:

第一次循环 (i = 0):

0x80 >> 0 = 10000000
01110101 & 10000000 = 00000000(零值)
零值 ? Bit_SET : Bit_RESET(Bit_RESET)

第二次循环 (i = 1):

0x80 >> 1 = 01000000
01110101& 01000000 = 01000000(非零值)
非零值 ? Bit_SET : Bit_RESET(Bit_SET)

第三次循环 (i = 2):

0x80 >> 1 = 00100000
01110101& 00100000= 00100000 (非零值)
非零值 ? Bit_SET : Bit_RESET(Bit_SET)

如此循环8次即可完成一个字节所有位的获取。

2. 设置特定位

按位或操作通常用于设置某些特定位为1,如下所示为设置number的第2位为1。

uint8_t number = 0b10100000;

现在我想要设置number的第2位为1(高位在左,低位在右)
number = number | 0b00000100; // 设置第2位为1
number = 0b10100100; // 二进制,十进制为 164

三、应用案例

3.1 应用案例代码

main.c:

#include <stdio.h>

#define	MPU6050_PWR_MGMT_1		0x6B // 0110 1011
#define	MPU6050_PWR_MGMT_2		0x6C // 0110 1100
#define	MPU6050_WHO_AM_I		0x75 // 0111 0101


typedef enum {
    Bit_RESET = 0,
    Bit_SET
} BitAction;

void MyI2C_W_SDA(int BitValue) {
    printf("BitValue:%d\n", BitValue);
}

void MyI2C_SendByte(unsigned char Byte) {
    int i;
    for (i = 0; i < 8; i++) {
        // 使用三元运算符将结果转换为 0 或 1
        MyI2C_W_SDA((Byte & (0x80 >> i)) ? Bit_SET : Bit_RESET);
    }
}

int main() 
{
    printf("MPU6050_WHO_AM_I,0x75 ---> 0111 0101\n");
    MyI2C_SendByte(MPU6050_WHO_AM_I);
    
    printf("MPU6050_PWR_MGMT_1,0x6B ---> 0110 1011\n");
    MyI2C_SendByte(MPU6050_PWR_MGMT_1);
    
    printf("MPU6050_PWR_MGMT_2,0x6C ---> 0110 1100\n");
    MyI2C_SendByte(MPU6050_PWR_MGMT_2);

    return 0;
}

输出结果如下:

jeff@jeff:/tmp$ ./main
MPU6050_WHO_AM_I,0x75 ---> 0111 0101
BitValue:0
BitValue:1
BitValue:1
BitValue:1
BitValue:0
BitValue:1
BitValue:0
BitValue:1
MPU6050_PWR_MGMT_1,0x6B ---> 0110 1011
BitValue:0
BitValue:1
BitValue:1
BitValue:0
BitValue:1
BitValue:0
BitValue:1
BitValue:1
MPU6050_PWR_MGMT_2,0x6C ---> 0110 1100
BitValue:0
BitValue:1
BitValue:1
BitValue:0
BitValue:1
BitValue:1
BitValue:0
BitValue:0
jeff@jeff:/tmp$

3.2 应用案例分析

相信通过上面的分析后大家对按位与按位或以及左移右移的操作已经心中有数了,这里我就不再累述了,在这里我只讲两点注意事项:

第一点,执行完 Byte & (0x80 >> i) 运算后结果仍然是一个8位1个字节的数据,只不过这个数据只有两个结果,0或者是非0。如果目标数据当前位为1,那么结果就是非0,如果目标数据当前位为0,那么结果就是0。可以通过三元运算的方式将0和非0转换成0和1。

第二点,三元运算符的语法是:

condition ? true_value : false_value;

condition 是一个表达式,计算后返回一个布尔值(trur or 1 或 false or 0)
如果 condition 为true or 1,那么整个表达式的结果是 true_value
如果 condition 为 false or 0,那么整个表达式的结果是 false_value

对应我们这里即,0就是Bit_RESET,1就是Bit_SET。

typedef enum {
    Bit_RESET = 0,
    Bit_SET
} BitAction;

MyI2C_W_SDA((Byte & (0x80 >> i)) ? Bit_SET : Bit_RESET);

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

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

相关文章

Java、python、php版 剧本杀拼团服务平台 剧本杀管理系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

谓词和量词

一、个体词和谓词 命题是一句陈述句&#xff0c;命题由个体词和谓词组成。 个体词是句子中的主语部分&#xff0c;比如这里的王童。 谓词是句子里的剩余部分&#xff0c;比如是一个三好学生 个体词用小写字母表示&#xff0c;谓词用大写字母&#xff0b;&#xff08;&#…

网络编程(学习)2024.8.29

目录 阻塞式IO(BIO) 特点 阻塞原因与阻塞反应 TCP流式套接字缓冲区 非阻塞式IO(NIO) 特点 设置非阻塞 1.通过对参数的修改实现 2.通过对文件描述符的属性进行设置 fcntl 信号驱动IO (异步IO模型) IO多路复用 select、poll、epoll IO多路复用机制 1.select …

深度学习实战2--MNIST 手写数字分类(代码在末尾)

1.本节目标&#xff1a; (1)了解什么是MNIST 数据集&#xff1b; (2)了解卷积神经网络对图片处理的流程&#xff1b; (3)能够看懂Python 编写的对图片分类任务的代码&#xff1b; (4)在一定程度上掌握处理类似任务的编程能力。 注意&#xff1a;本章节使用开源机器学习库P…

docker 部署 kkFileView 并 使用Nginx代理

拉取镜像 docker pull keking/kkfileview 运行容器 docker run -it -d -p 8012:8012 keking/kkfileview --restart always 配置nginx location /preview {# 本地运行的kkFileView的地址proxy_pass http://127.0.0.1:8012;proxy_set_header Host $host;proxy_set_header X-…

Sang.UAParser一个简单的.NET用户代理解析器

本文主要介绍了 Sang.UAParser 这个简单的.NET用户代理解析器&#xff0c;可以用来解析用户代理字符串&#xff0c;提取出其中的浏览器、操作系统等信息。这个库的使用非常简单&#xff0c;只需要引用 NuGet 包&#xff0c;然后调用相应的方法即可。 1. 简介 Sang.UAParser 是…

YOLO | YOLO目标检测算法(基础入门)

github&#xff1a;https://github.com/MichaelBeechan CSDN&#xff1a;https://blog.csdn.net/u011344545 YOLO目标检测算法 深度学习经典检测方法1、两阶段&#xff08;Two-stage&#xff09;2、单阶段&#xff08;One-stage&#xff09; 深度学习经典检测方法 1、两阶段&a…

blender修改材质时出现颜色丢失的问题

对于建立的三维模型&#xff0c;我们一般是直接使用gazebo时不会有材质的颜色信息&#xff0c;这一点还是比较烦的&#xff0c;所以这里通过blender来重新给模型上色 首先需要去安装blender&#xff1a; sudo apt install blender对于导入的模型,修改了材质后依然表现为没有颜…

如何在uni-app中使用echarts(泪的教训,保证可用,不能用来打我,保姆级教程)

线上最终实现图&#xff1a; 项目背景&#xff1a;uni-appvue2uv-uiecharts 每步都有坑&#xff0c;跟着看完 实现过程 使用了uniapp插件市场的 echarts-for-wx插件&#xff0c;以下两种方式均可 下载后将以下文件拷贝到项目的components下 如果是zip下载&#xff0c;解压后…

leetcode60.不同路径

题目描述 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例 1: 输入:m = 3, n = 7 输出:28 示例 2:…

OpenCV绘图函数(10)根据指定像素计算字体大小的函数getFontScaleFromHeight()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算特定字体的大小以达到给定的像素高度。 函数原型 double cv::getFontScaleFromHeight (const int fontFace,const int pixelHeight,const…

C_03_函数学习

函数 优点&#xff1a; 降低代码耦合度降低代码冗余度提高代码复用率提高代码可读性 思想&#xff1a; 封装【包装】 声明&#xff1a; 语法&#xff1a; extern 函数名(形参列表)&#xff1b;// 注意&#xff1a;此时 形参列表中变量名可以忽略不写&#xff1b;定义&#xff1…

风控领域特征工程

在金融行业&#xff0c;风险控制&#xff08;风控&#xff09;是核心环节&#xff0c;它关乎资产安全、合规性以及机构的长期稳健发展。随着大数据时代的到来&#xff0c;金融机构面临着前所未有的数据量和复杂性。在这样的背景下&#xff0c;风控领域特征工程应运而生&#xf…

构建高效公正的会议抽奖系统:提升活动互动性与参与度

在各类会议、庆典及企业活动中&#xff0c;抽奖环节往往是吸引参与者兴趣、增强活动氛围的关键一环。一个高效、公正且充满趣味性的会议抽奖系统&#xff0c;不仅能够极大地提升活动的互动性与参与度&#xff0c;还能加深品牌印象&#xff0c;促进与会者之间的交流与合作。本文…

数据结构线性表(1)顺序表

&#x1f30f;个人博客主页&#xff1a;意疏-CSDN博客 希望文章能够给到初学的你一些启发&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏支持一下笔者吧&#xff5e; 阅读指南&#xff1a; 开篇说明线性表的定义线性表的顺序存储结构&#xff08;顺序表…

全程云OA UploadEditorFile接口存在任意文件上传漏洞 附POC

@[toc] 全程云OA UploadEditorFile接口存在任意文件上传漏洞 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学…

中标麒麟v10 sp3 部署cuda cudnn tensorrt deepstream

1.驱动安装 ./NVIDIA-Linux-x86_64-530.41.03.run 更改,不检测 ./NVIDIA-Linux-x86_64-530.41.03.run -no-x-check 禁用nouveau 创建文件/etc/modprobe.d/blacklist-nouveau.conf,添加如下文本: blacklist nouveau options nouveau modeset=0 重新生成initramfs $ su…

压测工具大比武!谁是市场主流?

阿里云PTS 性能测试PTS&#xff08;Performance Testing Service&#xff09;是阿里云一款商业化的性能测试工具。支持按需发起压测任务&#xff0c;可支持百万并发、千万TPS流量发起能力&#xff0c;100%兼容JMeter。PTS支持的场景编排、API调试、流量定制、流量录制等功能&am…

【HarmonyOS】模仿个人中心头像图片,调用系统相机拍照,从系统相册选择图片和圆形裁剪显示 (一)

【HarmonyOS】头像图片&#xff0c;调用系统相机拍照&#xff0c;从系统相册选择图片和圆形裁剪显示 &#xff08;一&#xff09; Demo效果展示&#xff1a; 方案思路&#xff1a; 使用photoAccessHelper实现系统相册选择图片的功能。此API可在无需用户授权的情况下&#xff…

【Material-UI】Slider中的 Continuous Sliders 与 Sizes 详解

文章目录 一、Slider 组件概述1. 组件介绍2. 使用场景 二、Continuous Sliders 的详解1. Continuous Sliders 的作用2. Continuous Sliders 的基本用法3. 禁用状态下的 Continuous Sliders4. Continuous Sliders 的实际应用5. Continuous Sliders 的优缺点 三、Slider 的尺寸控…