位运算
- 格式:pdf
- 大小:328.63 KB
- 文档页数:21
位运算c++语言
位运算是一种对二进制位进行操作的运算。
在C++语言中,位操作运算符用于对整数类型的数据进行位操作。
以下是C++中常用的位运算操作符:
1. 按位与(&):将两个操作数的每个对应位进行与操作,生成一个新的数,对应位上的两个位都为1时,结果为1,否则为0。
2. 按位或(|):将两个操作数的每个对应位进行或操作,生成一个新的数,对应位上的任意一个位为1时,结果为1,否则为0。
3. 按位异或(^):将两个操作数的每个对应位进行异或操作,生成一个新的数,对应位上的两个位相同为0,不同为1。
4. 按位取反(~):对一个操作数的每个位进行取反操作,将0变为1,1变为0。
5. 左移(<<):将一个操作数的所有位向左移动指定的位数。
左移运算可以用于将二进制数乘以2的幂。
6. 右移(>>):将一个操作数的所有位向右移动指定的位数。
右移运算可以用于将二进制数除以2的幂。
位运算在许多情况下可以用于对数字进行高效的操作和处理,例如掩码操作、位探测、位计数等。
要注意的是,进行位运算时需要确保操作数的位数正确,否则结果可能不符合预期。
同时,位运算只能应用于整数类型的数据。
1/ 1。
⼏种常见的位运算1、判断奇偶数如果把⼀个数n以⼆进制数的形式表⽰的话,我们只需要判断最后⼀个⼆进制位是1还是0即可。
如果是1,则代表奇数,否则为偶数。
代码如下:if(n & 1 == 1){// n是奇数}2、交换两个数x = x ^ y; // (1)y = x ^ y; // (2)x = x ^ y; // (3)我们都知道两个相同的数异或之后的结果为0,即 n ^ n = 0,并且任何数与0异或之后等于它本⾝,即 n ^ 0 = n。
于是我们把(1)中的x代⼊(2)中的x,有:y = x ^ y = (x ^ y) ^ y = x ^ ( y ^ y) = x ^ 0 = x,这样x的值就赋给了y。
对于(3),推导如下:x = x ^ y = (x ^ y) ^ x = (x ^ x) ^ y = 0 ^ y = y,这样y的值就赋给了x。
异或运算⽀持运算的交换律和结合律。
3、找出没有重复的数给你⼀组整型数据,这些数据中,其中有⼀个数只出现了⼀次,其他的数都出现了两次,让你来找出⼀个数这道题可能很多⼈会⽤⼀个哈希表来存储,每次存储的时候,记录下某个数出现的次数,最后遍历哈希表找出只出现了⼀次的次数。
这种⽅式的时间复杂度是O(n),空间复杂度也为O(n)了。
其实这道题也可以进⾏位运算,,我们可以把这⼀组整型数全都异或,由于两个相同的数异或的结果为0,⼀个数与0异或的结果为其⾃⾝,所以异或的所得到的结果就为只出现了⼀次的数。
例如这组数据是:1, 2, 3, 4, 5, 1, 2, 3, 4。
其中 5 只出现了⼀次,其他都出现了两次,把他们全部异或⼀下,结果如下:1 ^2 ^3 ^4 ^5 ^ 1 ^ 2 ^ 3 ^ 4 = (1 ^ 1) ^ (2 ^ 2) ^ (3 ^ 3) ^ (4 ^ 4) ^ 5 = 0 ^ 0 ^ 0 ^ 0 ^ 5 = 5代码如下:int find(int[] nums){int tmp = nums[0];for(int i = 1;i < nums.length; i++)tmp ^= arr[i];return tmp;}4、2的n次⽅求解 2 的 n 次⽅,并且不能使⽤系统⾃带的 pow 函数很多⼈看到这个题可能觉得让n个2相乘就⾏了,如果这么做的话,时间复杂度为O(n)了。
位运算功能⼤全去掉最后⼀位:⽰例:(101101 \Rightarrow 10110)位运算:x>>1在最后加⼀个0⽰例:(101101\Rightarrow1011010)位运算:x<<1在最后加⼀个1⽰例:(101101\Rightarrow1011011)位运算:(x<<1)+1把最后⼀位变成1⽰例:(101100\Rightarrow101101)位运算:x|1把最后⼀位变成0⽰例:101101\Rightarrow101100位运算:(x|1)-1最后⼀位取反⽰例:(101101\Rightarrow101100)位运算:x^1把右数第k位变成1⽰例:(101001\Rightarrow101101,k=3)位运算:x|(1<<(k-1))把右数第k位变成0⽰例:(101101\Rightarrow101001,k=3)位运算:x\ and\ ~(1<<(k-1))右数第k位取反⽰例:(101001\Rightarrow101101,k=3)位运算:x (xor (1<<(k-1)))取整数n在⼆进制表⽰下的第k位位运算:(n>>k)\ and \ 1取整数n在⼆进制表⽰下的后k位位运算:n\ and\ ((1<<k)-1)取末k位⽰例:(1101101\Rightarrow1101,k=4)位运算:x\ and\ ((1<<k)-1)取右数第k位⽰例:(1101101\Rightarrow1,k=4)位运算:x>>(k-1)\ and\ 1把末k位变成1⽰例:(101001\Rightarrow101111,k=4位运算:x|((1<<k)-1)末k位取反⽰例:(101001\Rightarrow100110,k=4位运算:x\ xor\ ((1<<k)-1)把右边连续的1变成0⽰例:(100101111\Rightarrow100100000)位运算:x\ and\ (x+1)把右起第⼀个0变成1⽰例:(100101111\Rightarrow100111111位运算:x|(x+1)把右边连续的0变成1⽰例:(11011000\Rightarrow11011111)位运算:x|(x-1)取右边连续的1⽰例:(100101111\Rightarrow1111)位运算:(x\ xor\ (x+1))>>1去掉右起第⼀个1的左边⽰例:(100101000\Rightarrow1000)位运算:x\ and\ (x\ xor\ (x-1))Loading [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js。
execl 位运算
位运算是计算机中一种针对二进制位进行操作的运算方式。
在Excel中,位运算可以通过使用一些内置的函数来实现。
常见的位运算包括按位与(AND)、按位或(OR)、按位异或(XOR)、取反(NOT)等操作。
在Excel中,可以使用BITAND函数来进行按位与运算,BITOR 函数进行按位或运算,BITXOR函数进行按位异或运算,BITNOT函数进行取反操作。
这些函数可以用来处理二进制数据,比如IP地址的处理、权限控制等方面都会用到位运算。
另外,在Excel中也可以使用位运算符号来进行位运算操作。
例如,使用“&”符号进行按位与运算,使用“|”符号进行按位或运算,使用“^”符号进行按位异或运算,使用“~”符号进行取反操作。
位运算在Excel中可以用于处理一些需要对二进制数据进行操作的情况,比如网络编程、加密算法等。
通过灵活运用位运算,可以实现一些复杂的逻辑运算,提高数据处理的效率和灵活性。
总之,位运算在Excel中是一种重要的运算方式,可以通过内置函数或运算符号来实现对二进制数据的灵活处理,对于处理一些特定的数据场景具有重要的作用。
位运算是指按二进制进行的运算。
在系统软件中,常常需要处理二进制位的问题。
C语言提供了6个位操作运算符。
这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型。
C语言提供的位运算符列表:运算符含义描述& 按位与如果两个相应的二进制位都为1,则该位的结果值为1,否则为0| 按位或两个相应的二进制位中只要有一个为1,该位的结果值为1^ 按位异或若参加运算的两个二进制位值相同则为0,否则为1~ 取反 ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0 << 左移用来将一个数的各二进制位全部左移N位,右补0>> 右移将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补01、“按位与”运算符(&)按位与是指:参加运算的两个数据,按二进制位进行“与”运算。
如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。
这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。
按位与其实与逻辑上“与”的运算规则一致。
逻辑上的“与”,要求运算数全真,结果才为真。
若,A=true,B=true,则A∩B=true 例如:3&5 3的二进制编码是11(2)。
(为了区分十进制和其他进制,本文规定,凡是非十进制的数据均在数据后面加上括号,括号中注明其进制,二进制则标记为2)内存储存数据的基本单位是字节(Byte),一个字节由8个位(bit)所组成。
位是用以描述电脑数据量的最小单位。
二进制系统中,每个0或1就是一个位。
将11(2)补足成一个字节,则是00000011(2)。
5的二进制编码是101(2),将其补足成一个字节,则是00000101(2)按位与运算:00000011(2)&00000101(2)00000001(2)由此可知3&5=1c语言代码:#include <stdio.h>main(){int a=3;int b = 5;printf("%d",a&b);}按位与的用途:(1)清零若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合一下条件:原来的数中为1的位,新数中相应位为0。
c语言中位运算公式C语言中位运算公式在C语言中,位运算是对数据的二进制表示进行操作的一种运算。
位运算包括按位与(&)、按位或(|)、按位异或(^)、按位取反(~)以及左移(<<)和右移(>>)等操作。
这些运算符可以对整数类型的数据进行位级操作,具有高效、简洁的特点。
一、按位与运算(&)按位与运算符用来对两个操作数的二进制位进行与运算,即两个位都为1时结果为1,否则为0。
例如,对于两个整数a和b,a & b 的二进制位运算结果就是将a和b的二进制位对应的位进行与运算。
二、按位或运算(|)按位或运算符用来对两个操作数的二进制位进行或运算,即两个位只要有一个为1时结果为1,否则为0。
例如,对于两个整数a和b,a | b的二进制位运算结果就是将a和b的二进制位对应的位进行或运算。
三、按位异或运算(^)按位异或运算符用来对两个操作数的二进制位进行异或运算,即两个位相同为0,不同为1。
例如,对于两个整数a和b,a ^ b的二进制位运算结果就是将a和b的二进制位对应的位进行异或运算。
四、按位取反运算(~)按位取反运算符用来对操作数的二进制位进行取反运算,即将0变为1,1变为0。
例如,对于一个整数a,~a的二进制位运算结果就是将a的二进制位进行取反运算。
五、左移运算(<<)左移运算符用来将一个数的二进制位向左移动指定的位数,即在右边补0。
例如,对于一个整数a,a << n的二进制位运算结果就是将a的二进制位向左移动n位。
六、右移运算(>>)右移运算符用来将一个数的二进制位向右移动指定的位数,即在左边补0。
例如,对于一个整数a,a >> n的二进制位运算结果就是将a的二进制位向右移动n位。
位运算在C语言中具有很多应用场景。
其中,按位与运算常用于位掩码操作,按位或运算常用于设置标志位,按位异或运算常用于数据加密与解密,按位取反运算常用于数据反转等。
位运算加减乘除位运算是计算机科学中一种重要的运算方法。
它的操作对象是一个二进制的数字,通过位运算可以实现加减乘除等运算。
可以节省计算机在运算过程中的时间和空间,提高计算机的运行效率。
位运算中最基本的操作是位与,称为逻辑与。
它把第一个参数与第二个参数每个位都进行逻辑“与”(AND)的操作,结果也是0或者1的形式。
逻辑“或”(OR)的运算,用来确定第一个参数或者第二个参数中有一个为1,则结果为1,否则结果就是0,也就是逻辑“求和”(SUM)的运算。
除了逻辑运算,位运算还包括“移位”(SHIFT)和“反转”(ROTATE),它们都是对二进制数据进行位移操作。
其中,SHIFT用来把二进制数据往左或往右移动一定数量的位,这个操作会使用改变原始数据,这种操作会使数值变大或变小。
而ROTATE则是把二进制数据的最高位移到最低位,以此改变其原始值,这一操作可以实现数据的加法、减法、乘法和除法等计算。
加法和减法的操作由“计数”(count)和“反计数”(count-down)两种模式构成,“计数”是正值的运算,即“加法”,而“反计数”则是负值的运算,即“减法”,次计算后都会把结果保存在一个寄存器中,循环累加和累减运算,直到得到最终结果。
乘法和除法的操作由“乘法模块”( multiplyer )和“除法模块”( divisor )两种模式构成。
“乘法模块”是将两个二进制数相乘,即把第一个参数乘以第二个参数,并把结果保存在寄存器中,而“除法模块”则是将第一个参数除以第二个参数,把结果保存在寄存器中。
位运算的技术在计算机科学中得到了广泛的应用。
它将大量的运算合并成一步,可以提高计算机的运算速度,并可以节省计算机内存的使用空间。
位运算同时也可用于网络的技术校验,比如校验网络数据的完整性等。
总之,位运算加减乘除是一种重要的计算机科学技术,它的优势是它把复杂的计算任务简化成一个步骤,可以提高计算机的运行效率,而且可以节省计算机存储器的空间,因此它已经得到了广泛的应用。
位运算简介及实用技巧(一):基础篇什么是位运算?程序中的所有数在计算机内存中都是以二进制的形式储存的。
位运算说穿了,就是直接对整数在内存中的二进制位进行操作。
比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。
举个例子,6的二进制是110,11的二进制是1011,那么6and11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理):110AND1011----------0010-->2由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。
当然有人会说,这个快了有什么用,计算6and11没有什么实际意义啊。
这一系列的文章就将告诉你,位运算到底可以干什么,有些什么经典应用,以及如何用位运算优化你的程序。
Pascal和C中的位运算符号下面的a和b都是整数类型,则:C语言|Pascal语言-------+-------------a&b|a and ba|b|a or ba^b|a xor b~a|not aa<<b|a shl ba>>b|a shr b注意C中的逻辑运算和位运算符号是不同的。
520|1314=1834,但520||1314=1,因为逻辑运算时520和1314都相当于True。
同样的,!a和~a也是有区别的。
各种位运算的使用===1.and运算===and运算通常用于二进制取位操作,例如一个数and1的结果就是取二进制的最末位。
这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数.===2.or运算===or运算通常用于二进制特定位上的无条件赋值,例如一个数or1的结果就是把二进制最末位强行变成1。
如果需要把二进制最末位变成0,对这个数or1之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。
===3.xor运算===xor运算通常用于对二进制的特定一位进行取反操作,因为异或可以这样定义:0和1异或0都不变,异或1则取反。
xor运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a xor b)xor b=a。
xor运算可以用于简单的加密,比如我想对我MM说1314520,但怕别人知道,于是双方约定拿我的生日19880516作为密钥。
1314520xor 19880516=20665500,我就把20665500告诉MM。
MM再次计算20665500xor19880516的值,得到1314520,于是她就明白了我的企图。
下面我们看另外一个东西。
定义两个符号#和@(我怎么找不到那个圈里有个叉的字符),这两个符号互为逆运算,也就是说(x#y)@y=x。
现在依次执行下面三条命令,结果是什么?x<-x#yy<-x@yx<-x@y执行了第一句后x变成了x#y。
那么第二句实质就是y<-x#y@y,由于#和@互为逆运算,那么此时的y变成了原来的x。
第三句中x实际上被赋值为(x#y)@x,如果#运算具有交换律,那么赋值后x就变成最初的y了。
这三句话的结果是,x和y的位置互换了。
加法和减法互为逆运算,并且加法满足交换律。
把#换成+,把@换成-,我们可以写出一个不需要临时变量的swap 过程(Pascal)。
procedure swap(var a,b:longint);begina:=a+b;b:=a-b;a:=a-b;end;好了,刚才不是说xor的逆运算是它本身吗?于是我们就有了一个看起来非常诡异的swap过程:procedure swap(var a,b:longint);begina:=a xor b;b:=a xor b;a:=a xor b;end;===4.not运算===not运算的定义是把内存中的0和1全部取反。
使用not运算时要格外小心,你需要注意整数类型有没有符号。
如果not的对象是无符号整数(不能表示负数),那么得到的值就是它与该类型上界的差,因为无符号类型的数是用$0000到$FFFF依次表示的。
下面的两个程序(仅语言不同)均返回65435。
vara:word;begina:=100;a:=not a;writeln(a);end.#include<stdio.h>int main(){unsigned short a=100;a=~a;printf("%d\n",a);return0;}如果not的对象是有符号的整数,情况就不一样了,稍后我们会在“整数类型的储存”小节中提到。
===5.shl运算===a shl b就表示把a转为二进制后左移b位(在后面添b个0)。
例如100的二进制为1100100,而110010000转成十进制是400,那么100shl2=400。
可以看出,a shl b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。
通常认为a shl1比a*2更快,因为前者是更底层一些的操作。
因此程序中乘以2的操作请尽量用左移一位来代替。
定义一些常量可能会用到shl运算。
你可以方便地用1shl16-1来表示65535。
很多算法和数据结构要求数据规模必须是2的幂,此时可以用shl来定义Max_N等常量。
===6.shr运算===和shl相似,a shr b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。
我们也经常用shr1来代替div2,比如二分查找、堆的插入操作等等。
想办法用shr代替除法运算可以使程序效率大大提高。
最大公约数的二进制算法用除以2操作来代替慢得出奇的mod运算,效率可以提高60%。
位运算的简单应用有时我们的程序需要一个规模不大的Hash表来记录状态。
比如,做数独时我们需要27个Hash表来统计每一行、每一列和每一个小九宫格里已经有哪些数了。
此时,我们可以用27个小于2^9的整数进行记录。
例如,一个只填了2和5的小九宫格就用数字18表示(二进制为000010010),而某一行的状态为511则表示这一行已经填满。
需要改变状态时我们不需要把这个数转成二进制修改后再转回去,而是直接进行位操作。
在搜索时,把状态表示成整数可以更好地进行判重等操作。
这道题是在搜索中使用位运算加速的经典例子。
以后我们会看到更多的例子。
下面列举了一些常见的二进制位的变换操作。
功能|示例|位运算----------------------+---------------------------+--------------------去掉最后一位|(101101->10110)|x shr1在最后加一个0|(101101->1011010)|x shl1在最后加一个1|(101101->1011011)|x shl1+1把最后一位变成1|(101100->101101)|x or1把最后一位变成0|(101101->101100)|x or1-1最后一位取反|(101101->101100)|x xor1把右数第k位变成1|(101001->101101,k=3)|x or(1shl(k-1))把右数第k位变成0|(101101->101001,k=3)|x and not(1shl(k-1))右数第k位取反|(101001->101101,k=3)|x xor(1shl(k-1))取末三位|(1101101->101)|x and7取末k位|(1101101->1101,k=5)|x and(1shl k-1)取右数第k位|(1101101->1,k=4)|x shr(k-1)and1把末k位变成1|(101001->101111,k=4)|x or(1shl k-1)末k位取反|(101001->100110,k=4)|x xor(1shl k-1)把右边连续的1变成0|(100101111->100100000)|x and(x+1)把右起第一个0变成1|(100101111->100111111)|x or(x+1)把右边连续的0变成1|(11011000->11011111)|x or(x-1)取右边连续的1|(100101111->1111)|(x xor(x+1))shr1去掉右起第一个1的左边|(100101000->1000)|x and(x xor(x-1))最后这一个在树状数组中会用到。
Pascal和C中的16进制表示Pascal中需要在16进制数前加$符号表示,C中需要在前面加0x来表示。
这个以后我们会经常用到。
整数类型的储存我们前面所说的位运算都没有涉及负数,都假设这些运算是在unsigned/word类型(只能表示正数的整型)上进行操作。
但计算机如何处理有正负符号的整数类型呢?下面两个程序都是考察16位整数的储存方式(只是语言不同)。
vara,b:integer;begina:=$0000;b:=$0001;write(a,'',b,'');a:=$FFFE;b:=$FFFF;write(a,'',b,'');a:=$7FFF;b:=$8000;writeln(a,'',b);end.#include<stdio.h>int main(){short int a,b;a=0x0000;b=0x0001;printf("%d%d",a,b);a=0xFFFE;b=0xFFFF;printf("%d%d",a,b);a=0x7FFF;b=0x8000;printf("%d%d\n",a,b);return0;}两个程序的输出均为01-2-132767-32768。
其中前两个数是内存值最小的时候,中间两个数则是内存值最大的时候,最后输出的两个数是正数与负数的分界处。
由此你可以清楚地看到计算机是如何储存一个整数的:计算机用$0000到$7FFF依次表示0到32767的数,剩下的$8000到$FFFF依次表示-32768到-1的数。
32位有符号整数的储存方式也是类似的。
稍加注意你会发现,二进制的第一位是用来表示正负号的,0表示正,1表示负。
这里有一个问题:0本来既不是正数,也不是负数,但它占用了$0000的位置,因此有符号的整数类型范围中正数个数比负数少一个。
对一个有符号的数进行not运算后,最高位的变化将导致正负颠倒,并且数的绝对值会差1。
也就是说,not a实际上等于-a-1。