跳转至

img

位运算

本片是分享关于位运算的笔记

一、前言

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;
}

最后更新: 2022-03-07 08:58:56

评论

回到页面顶部