位运算¶
本片是分享关于位运算的笔记
一、前言¶
1.1配套视频链接¶
https://www.bilibili.com/video/BV1gL411c7eG
1.2原码、反码、补码¶
https://blog.csdn.net/m0_46201544/article/details/121818968?spm=1001.2014.3001.5501
计组的内容,可以去搜一下先了解
二、位运算¶
2.1 &按位与¶
2.1.1 定义¶
如果两个相应的 二进制位 都为1,则该位的结果值为1,否则为0
2.1.2 举例¶
对于这样两个数:3、5,我们先将其转化为为二进制:
\(3=(0011)_2\)
\(5=(0101)_2\)
那么我们对其进行按照位与操作可得:\((0001)_2\)也就是1
代码实现:
#include<stdio.h>
int main()
{
int a = 3,b = 5;
printf("a&b = %d\n",a&b);
return 0;
}
2.2 | 按位或¶
2.2.1定义¶
两个相应的 二进制位 中只要有一个为1,该位的结果值为1
2.2.2举例¶
对于这样两个数:3、5,我们先将其转化为为二进制:
\(3=(0011)_2\)
\(5=(0101)_2\)
那么我们对其进行按照位或操作可得:\((0111)_2\)也就是7
代码实现:
#include<stdio.h>
int main()
{
int a = 3,b = 5;
printf("a|b = %d\n",a|b);
return 0;
}
2.3 ^ 按位异或¶
2.3.1 定义¶
若参加运算的两个二进制位值相同则为0,否则为1
2.3.2 举例¶
对于这样两个数:3、5,我们先将其转化为为二进制:
\(3=(0011)_2\)
\(5=(0101)_2\)
那么我们对其进行按照位或操作可得:\((0110)_2\)也就是6
代码实现:
#include<stdio.h>
int main()
{
int a = 3,b = 5;
printf("a^b = %d\n",a^b);
return 0;
}
2.4 ~ 取反¶
2.4.1 定义¶
~是一元运算符,用于求整数的二进制补码,即分别将操作数各二进制位上的1变为0,0变为1。
2.4.2 举例¶
对于一个数字1,我们先对其转化为二进制并转化为补码:\((00000001)_H\)然后取反,那么可以得到:\((FFFFFFFE)_H\),然后我们再求该数的原码则得:-2
代码实现:
#include<stdio.h>
int main()
{
int a = 1;
printf("~a = %d",~a);
return 0;
}
2.5 << 左移¶
2.5.1 定义¶
用来将一个数的各二进制位全部左移N位,右补0
效果等价将该数乘二
2.6 举例¶
#include<stdio.h>
int main()
{
int a = 1;
printf("a<<2 = %d",a<<2);
return 0;
}
2.7 >> 右移¶
2.7.1 定义¶
将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0
效果等价将该数除二
2.7.2 举例¶
#include<stdio.h>
int main()
{
int a = 7;
printf("a>>2 = %d",a>>1);
return 0;
}
2.8 一些应用¶
例如:
2.8.1 将该数的某一位设置为1¶
我们通过左移和或位运算即可将该数的某一位设置为1,或者是判断是否为1
eg:x|(1<<10)
:将从右往左第十个位置设为1
2.8.2 两个相同的异或值为0¶
如标题,可以和我们上次学的前缀和结合起来,并且根据这个性质我们能写出不需要零时变量数的SWAP函数
2.8.3 通过&运算判断数n是否为奇数¶
我们将n和1进行位与操作就能判断,因为奇数和偶数我们只需要判断最后一位是否为1即可
if(n&1){
puts("奇数");
}
else{
puts("偶数");
}
2.8.4 取int型变量a的第k位¶
\((k=0,1,2……sizeof(int))\)
a>>k&1
更多技巧请参考这篇文章:
https://zhuanlan.zhihu.com/p/54946559
三、位运算相关函数¶
3.1 __builtin_popcount(unsigned int n)
¶
该函数时判断n的二进制中有多少个1
eg:
int n = 15; //二进制为1111
cout<<__builtin_popcount(n)<<endl;//输出4
3.2 __builtin_parity(unsigned int n)
¶
该函数是判断n的二进制中1的个数的奇偶性
eg:
int n = 15;//二进制为1111
int m = 7;//111
cout<<__builtin_parity(n)<<endl;//偶数个,输出0
cout<<__builtin_parity(m)<<endl;//奇数个,输出1
3.3 __builtin_ffs(unsigned int n)
¶
该函数判断n的二进制末尾最后一个1的位置,从一开始
eg:
int n = 1;//1
int m = 8;//1000
cout<<__builtin_ffs(n)<<endl;//输出1
cout<<__builtin_ffs(m)<<endl;//输出4
3.4 __builtin_ctz(unsigned int n)
¶
该函数判断n的二进制末尾后面0的个数,当n为0时,和n的类型有关
eg:
int n = 1;//1
int m = 8;//1000
cout<<__builtin_ctzll(n)<<endl;//输出0
cout<<__builtin_ctz(m)<<endl;//输出3
3.5 __builtin_clz (unsigned int x)
¶
该函数判断n的二进制前导的0的个数。
eg:
#include<stdio.h>
int main()
{
int a = 1<<30;
printf("%d\n",__builtin_clz (a));//输出1
return 0;
}