聊聊位运算一些注意事项

news/2024/12/26 0:25:55/文章来源:https://www.cnblogs.com/DSCL-ing/p/18414567

目录
  • 位运算
    • 位运算和逻辑运算区别
    • 位运算的几点注意
    • 异或的运算规则
    • 异或的经典问题:两数交换
    • 位操作建议使用宏定义好后使用
    • 位运算整型提升问题
  • 左移和右移
    • 概念
    • 移位运算容易误解成移位赋值

位运算


位运算和逻辑运算区别

位运算是一位对应一位的对所有位逐一进行运算(逐比特位进行运算).逻辑运算是以计算表达式的真假为主进行运算.


位运算的几点注意

  1. 机器都是使用补码进行运算,遇到负数时不要混淆

  2. ~(-1)的结果是0,~(0)的结果是-1,按位取反所有位都要取反,不论是否有符号.


异或的运算规则

  1. 运算规则: 相同为假, 相异为真

    0000 0000 ... 0100
    0000 0000 ... 0011
    

0000 0000 ... 0111
printf("%d\n",4^3); //结果:7

2. 任何数据和0异或,结果都是它本身
```C
printf("%d\n",1 ^ 0);  //结果:1
printf("%d\n",6 ^ 0);  //结果:6
printf("%d\n",7 ^ 0);  //结果:7
printf("%d\n",-1 ^ 0); //结果:-1
  1. 异或运算支持交换律和结合律

    printf("%d\n",5 ^ 5 ^ 4);   //结果:4
    printf("%d\n",5 ^ 4 ^ 5);   //结果:4 => 交换律
    printf("%d\n",5 ^ (5 ^ 4)); //结果:4 => 结合律
    
  2. 异或自己的结果是0 (消消乐)


异或的经典问题:两数交换

问题:两个变量int a = 10; int b = 20;再不使用第三个变量的前提下,怎么讲两个数进行交换?

方法一:加减法

    a = a + b;  // ①b = a - b;  // ②a = a - b;  // ③

解析:

(在计算机运算中,运算过程可以当作第三个变量,只是这个过程必须赋值才有意义,我们可以计算出各种组合的值用来匹配和验证)

  1. ①是将a和b的值保存到a中.原理:a+b-b = a,只要b还在,a就不会丢失.(借助a当作第三个容器)
  2. ②:验证发现新a-b = 旧a,赋值给b后就能实现b变成了旧a.
  3. ③:a变量保存着旧a和旧b,新b保存旧a,于是新a-新b就等于旧b.

缺点: 加法可能会有比特位递增,如果发生溢出,则会发生截断,导致数据丢失.所以这种方法仅适用于一定范围的数据


方法二:异或法

    a = a ^ b; //①b = a ^ b; //②a = a ^ b; //③
一次记住它: 等号左边是aba,右边全是a^b

解析:(消消乐)

  1. ①是a和b的值保存在a中.原理:a^b^b=a,只要b还在a就不会丢失.
  2. ②: 新a=10^20,对b=a^b=10^20^20,利用结合律,先计算20^20,就可以得到a,然后再赋值给b,b变量就得到了旧a的值.
  3. ③:有了旧a的值,交换律+消消乐把新a中旧a的值消掉,新a就可以得到旧b的值,完成交换.

相对于加减法的优点: 异或不会进位,不会出现比特位递增、溢出的问题


位操作建议使用宏定义好后使用

// 0|0 = 0 ; 0|1 = 1  //  规律:任何数或0结果都是它本身      //用途:
// 1|0 = 1 ; 1|1 = 1  //  规律:任何数或1,结果都是被设置为1  //用途:特定 比特位 置1
// 组合用途:让特定比特位置1,其他位不变// 0&0 = 0 ; 0&1 = 0; //  规律:任何书与0,结果都是被设置成0  //用途:特定比特位置0
// 1&0 = 0 ; 1&1 = 1; //  规律:任何书与1,结果都是它本身     //用途:获取特定比特位的值
// 组合用途:没有干扰地获取特定比特位的值//一般都是用1(000...1)比较方便,通过移动1的位置,加上不同的位运算符,能够实现不同的功能.#define SETBIT(x,n)  (x |= (1<<(n-1))) //统一体现: 宏函数:宏加上了函数圆括号()就成了宏函数.普通函数不带分号,宏函数也不要带分号
#define CLRBIT(x,n)   (x &= ~(1<<(n-1))) //移位后取反void ShowBits(int x) //打印x的补码序列
{int num = sizeof(int) * 8;while (num){if (x & (1 << (num - 1))){printf("1");}else{printf("0");}num--;};puts("");}int main()
{int x = 0;ShowBits(x);SETBIT(x,5);SETBIT(x,32);SETBIT(x,1);ShowBits(x);CLRBIT(x,5);CLRBIT(x,1);CLRBIT(x,32);ShowBits(x);return 0;```

打印结果:
位操作的结果


位运算整型提升问题

如图
373c2fa7-db98-44f4-8bfe-3958956c0d13


为什么对char类型位操作后进行sizeof,计算出来的大小会改变? 难道位操作后就不是char类型吗? 并不是
解析:

首先,C语言关键字的作用是在编译期间就确定好了.sizeof是C语言关键字,他在编译期间就确定好了大小.换言之,sizeof这个计算过程是在编译期间做的,通过反汇编,我们能看到汇编代码中sizeof不存在,只显示了一个常数,这也说明sizeof不是一个函数,它在编译期间就已经计算好了.

其次,不论任何位运算符,目标都是要计算机进行计算的,需要加载到CPU中进行计算. 但是计算的数据都是存放在内存中,要计算都必须从内存加载到cpu中.拿到CPU那里? 答案是cpu的寄存器中.而寄存器本身,随着计算机位数的不同,寄存器的位数也不同.一般在32位下.寄存器的位数是32位.因为char是8位,读到寄存器中,只能填补低8位,还有高24位没有数据,因此就会触发整型提升,然后计算,这也是说明数据在计算机中并非以char类型运行,都是以整型方式运行的.综上这一些系列步骤,编译成的汇编代码就是整型提升后的大小了

汇编部分截图:

image-20240501125546849


在vs中还有一种现象:sizeof(!c)大小不同编译器大小不一样

如图:

image-20240501131543968按照前面四种类型的分析,理论上也应该是4,而vs是1,gcc是4,这也是说明了具体的整型提升方式也是由编译器决定的,原理大致就是这样.


左移和右移


概念

<<(左移): 最高位丢弃,最低位补零
>>(右移):

  1. 无符号数:最低位丢弃,最高位补零[逻辑右移]
  2. 有符号数:最低位丢弃,最高位补符号位[算术右移]
    (无符号数,要保证它始终无符号,所以逻辑右移高位补零)

右移相当于除以2,但有特殊情况,有符号数且为-1时,右移数值不会改变
左移始终补零,所以都是乘以2
实际上,浮点数的左移右移坑还是很多,尽量不使用浮点数.非要使用,先在编译器下提前验证好再使用


移位运算容易误解成移位赋值

移位运算也和其他运算一样,加载到cpu中计算,并不会写回到内存中,只有赋值才能将数据写回内存

int a = 10;
a << 1; //a的值没有改变
a <<=1; //a的值改变了
a = a<<1;//a的值改变了

数据在做计算时,要将数据内存加载到CPU寄存器中,在CPU内的数据改变,是不会影响到内存中的数据,这里会有短暂的时间CPU与内存的值是不一样的,直到我们把结果写回到内存中.在加载到CPU直到写回内存这段过程的每一段都有可能体现在代码中,具体取决于编译器怎么处理(不同编译器计算路径不唯一).


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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

频繁改版惹人烦?火山引擎数据飞轮两招直击APP痛点促增长

APP精准有效的自我迭代,能够为其带来用户粘性增强与活跃度增长,而随之不断增长的用户使用量又会带来更加丰富的数据,从而支撑 APP 实现更为精准科学的洞察。更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 你应该遇到过这样的情况:…

易优eyoucms网站安装一直显示未知错误,无法继续

遇到“未知错误”并且在多台服务器上都无法完成安装的情况,可能是因为一些特定的环境配置问题。根据提供的信息,这里有几个可能的原因及解决方法:数据库版本问题:如果数据库版本较高(例如MySQL 8.x),而EyouCMS仅支持较旧的版本(如MySQL 5.6),那么将数据库版本回退到E…

易优eyoucms网站数据库文件版本号(v1.3.9)与CMS源码版本号(v1.4.1)不一致,无法安装,如何解决?

当遇到数据库文件版本号与CMS源码版本号不一致的问题时,可以采取以下两种方法来解决: 第一种方法:回原网站备份数据库再搬家回到原网站备份数据库:登录原网站的数据库管理系统(如phpMyAdmin或通过命令行)。 备份整个数据库。 导出数据库文件,并保存到本地。在新服务器上…

易优eyoucms网站安装报错 Service Unavailable

当你在安装EyouCMS时遇到"Service Unavailable"错误,这通常意味着Web服务器(如IIS或Apache)无法处理请求,可能是由于资源限制、配置问题或其他服务器端的问题。以下是一些可能的解决方案:检查服务器资源:确认服务器是否有足够的资源(CPU、内存、磁盘空间)来运…

宝塔Linux面板搭建开源考试系统phpems

一、安装宝塔linux面板 1、宝塔linux面板官网:https://baota.yingxunszcm.cn/2、安装宝塔linux面板,使用万能安装脚本if [ -f /usr/bin/curl ];then curl -sSO download.cnnbt.net/install_panel.sh;else wget -O install_panel.sh download.cnnbt.net/install_panel.sh;fi;b…

数字图像处理-实验4

实验4:几何变换与变形 实验4.1:图像透视变换将一幅输入图像变换为任意一个指定的四边形形状(给定四边形4个顶点)。提示:根据4个顶点的对应估计一个透视变换H,再用H对原图像进行形变(OpenCV相关函数:getPerspectiveTransform, warpPerspective等)设计一个交互程序,可以…

外观

1.加入外观的步骤:外观是GAP服务的一个特征,外观的值是在GAP初始化函数里面设置的,广播初始化时只能选择广播包中是否包含外观,而不能设置外观的值。所以,配置外观的步骤是首先在GAP初始化函数中根据实际应用设置外观特征的值,然后在广播初始化函数中设置包含或不包含外观…

Centos7.9安装部署Gitlab

环境准备系统 IP 配置centos7.9(图形化) 192.168.8.180 2c4g--300GGitlab介绍GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。GitLab由乌克兰程序员DmitriyZaporozhets和ValerySizov开发,它由Ruby写成。后来,一些部分用…

.Net Mvc中JS如何让获取Session

参考来源:C#MVC中JS如何获取Session-百度经验 (baidu.com) 1)将session信息隐藏到界面上,再通过JS找到这个隐藏字段获取值2)页面初始化的时候,直接将session的值赋值给JS变量 3)JS发起一次Ajax请求,从服务器获取session值

【运维自动化-配置平台】如何查看运营数据和审计

操作审计记录了主机、业务等资源纬度的操作记录,也可以根据操作动作来查询操作审计 查看某主机操作历史 包括主机的模块转移、属性修改等查看某业务的操作历史 包括业务、模块、集群、服务模板等资源的变更记录查看资源类型的操作历史查看其他类型的操作历史,如模型分组运营统…

易优eyoucms网站安装时出现“数据库连接失败,请重新设定”的错误

遇到易优CMS在安装时出现“数据库连接失败,请重新设定”的错误,通常是因为数据库连接信息不正确或环境配置问题。以下是一些详细的解决步骤: 解决步骤检查数据库连接信息 检查数据库状态 检查防火墙和安全组设置 检查数据库用户权限 清理安装锁文件 手动导入数据库1. 检查数…

uniapp打包解决模拟器没法安装问题

打开项目的manifest.json文件,在 “App常用其它设置” -> “Android设置” -> “支持CPU类型” 项中勾选需要支持的CPU类型: 参考新文档地址:https://uniapp.dcloud.io/tutorial/app-android-abifilters