位运算及其应用

位运算及其应用详解(转)

位运算基本概念及简单运用
C语言提供了六种位运算符:

&     按位与
|      按位或
^      按位异或
~      取反
<<    左移,相当与*2
>>    右移,正数高位补0,负数由计算机决定
循环左移k次 (x<<k) | (x >> (32-k)),
循环右移k次 (x>>k) | (x << (32-k))
当然常常应为优先级问题而犯错~~~
优先级及口诀如下
优先级别运算符记忆口诀
()  []  .  ->
括号成员第一;        //括号运算符[]() 成员运算符.  ->
全体单目第二;        //所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算*、&
乘除余三,加减四;   //这个"余"是指取余运算即%
移位五,关系六;    //移位运算符:<< >> ,关系:> < >= <= 等
等于(与)不等排第七;    //即== 和!=
位与异或和位或;    //这几个都是位运算: 位与(&)异或(^)位或(|)    
"三分天下"八九十;  
逻辑或跟与;            //逻辑运算符:|| 和 &&
十二和十一;            //注意顺序:优先级(||)  底于 优先级(&&) 
条件高于赋值,        //三目运算符优先级排到13 位只比赋值运算符和","高
逗号运算级最低!    //逗号运算符优先级最低 

2
 !  ~   -(负号)
++  --   &(取变量地址) *
(type)(强制类型)    sizeof 
3 * / %
4+   - 
5 >>    <<  
6>    >=    <    <= 
7==    !=   
8&
9^
10|
11&&
12||
13?:
14=  +=  -=  *=  /=   %=  |=   ^=   &=   >>=   <<=
15,
按位与运算
按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。
例如:9&5可写算式如下:
    00001001      (9的二进制补码)
    &00000101    (5的二进制补码)
    00000001       (1的二进制补码)
可见9&5=1。
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 ,保留低八位,可作a&255运算(255 的二进制数为0000000011111111)。
按位或运算
按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
例如:9|5可写算式如下:
    00001001
    |00000101
    00001101    (十进制为13)
可见9|5=13
按位异或运算
按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现,例如9^5可写成算式如下:
    00001001
    ^00000101 
    00001100    (十进制为12)
求反运算
求反运算符~为单目运算符,具有右结合性。其功能是对参与运算的数的各二进位按位求反。例如~9的运算为:
    ~(0000000000001001)
结果为:1111111111110110
左移运算
左移运算符“<<”是双目运算符。其功能把“<< ”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0。例如:
    a<<4
指把a的各二进位向左移动4位。如a=00000011(十进制3),左移4位后为00110000(十进制48)。
右移运算
右移运算符“>>”是双目运算符。其功能是把“>>”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。例如:
    设  a=15,
    a>>2
表示把000001111右移为00000011(十进制3)。
注意:对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,
         最高位是补0或是补1 取决于编译系统的规定。Turbo C和很多系统规定为补1。
简单运用
一:交换两个数(字符),不用第三个变量就可以交换两个变量的值了:
      用异或^,原理:两次异或能还原,即a = (a^b) ^ b
二:判断一个数是不是2的幂次:
     原理:2的幂次的二进制表示中只有一位是1,其他位为0
     x = x&(x-1)是让x的二进制码最右侧的1置为0,如果结果为0就表示原先x只有1位是1,其他位为0
     inline bool is2pow(int x) { return (x&(x-1)==0 && (x!=0)); }
     inline bool is2pow(int x) { return ( (x&-x)==x ); }
三:求一个整数有多少位是0:
      原理同上。用x&(x-1)

1int  count = 0;
2while(x)
3{
4    ++count;
5    x &= (x-1);
6 }

四:二进制快速求幂:

1long pow(int x, unsigned int n){
2long p = 1;
3while (n){
4if (n & 1) p *= x;
5         x *= x;
6         n >>= 1;
7    }
8return p;
9 }

五:判断奇偶数:
     原理:奇数最后一位为1,偶数为0
     inline bool odd(int x) { return x&1; }
     inline bool even(int x) {return !(x&1); } 
     n%2 = n&1
     n%4 = n&3
     n%8 = n&7
     ……
六:求x绝对值:
     原理:x为正数时不做改变,为负数时取反加1
     x为正数时y = 0 = 0000 0000 0000 0000
     x为负数时y = -1 = 1111 1111 1111 1111
     跟0异或是本身,跟1异或是取反
1 inline int abs(int x){
2int y = x >> 31;
3return ( x^y-y);
4 }
七:对2的幂次取模:
     原理:x&y取出x和y二进制位1的所有位。x^y>>1取出x,y只有一个二进制位1的并除以2
     return (x&y) + (x^y)>>1);
     不用位运算时注意 (x+y)/2,有可能会溢出。
     x向上取整到y,其中y=2^n (字节对齐用):
     #define rund(x,y) ( ((x)+(y)-1)&~((y)-1) )
八:其他:
    只有第k位为1的数 1 << (k-1)
    后k位为均为1的数 (1<<k)-1
    x 的第k+1位 x >> k &1
    x的第k+1位置1: x >> k |(1 << k)
    x的第k+1位置0: x >> k &~(1 << k) 
    注意:左移1位再右移1位不一定时原先的值
至于高深用法可以戳戳这里 

-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------


 一.逻辑运算符 
1.& 位与运算 
 1) 运算规则 
位与运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑与运算。例如:int型常量4和7进行位与运算的运算过程如下:
4=0000 0000 0000 0100 &7 =0000 0000 0000 0111= 0000 0000 0000 0100
对于负数,按其补码进行运算。例如:例如:int型常量-4和7进行位与运算的运算过程如下: -4=1111 1111 1111 1100 &7 =0000 0000 0000 0111= 0000 0000 0000 0100
2) 典型应用 
(1) 清零 
清零:快速对某一段数据单元的数据清零,即将其全部的二进制位为0。例如整型数a=321对其全部数据清零的操作为a=a&0x0。 321=0000 0001 0100 0001 &0=0000 0000 0000 0000
= 0000 0000 0000 0000
(2) 获取一个数据的指定位 
获取一个数据的指定位。例如获得整型数a=的低八位数据的操作为a=a&0xFF。321=
0000 0001 0100 0001 & 0xFF =0000 0000 1111 11111
= 0000 0000 0100 0001
获得整型数a=的高八位数据的操作为a=a&0xFF00。==a&0XFF00==
321=0000 0001 0100 0001 & 0XFF00=1111 1111 0000 0000
= 0000 0001 0000 0000
(3)保留数据区的特定位  
保留数据区的特定位。例如获得整型数a=的第7-8位(从0开始)位的数据操作为: 110000000
321=0000 0001 0100 0001 & 384=0000 0001 1000 0000
=0000 0001 0000 0000
2. | 位或运算 
1) 运算规则 
位或运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑或运算。例如:int型常量5和7进行位或运算的表达式为5|7,结果如下:5= 0000 0000 0000 0101
| 7= 0000 0000 0000 0111=0000 0000 0000 0111
2) 主要用途 
(1) 设定一个数据的指定位。例如整型数a=321,将其低八位数据置为1的操作为a=a|0XFF。321= 0000 0001 0100 0001 | 0000 0000 1111 1111=0000 0000 1111 1111
逻辑运算符||与位或运算符|的区别 
条件“或”运算符 (||) 执行 bool 操作数的逻辑“或”运算,但仅在必要时才计算第二个操作数。 x || y , x | y 不同的是,如果 x 为 true,则不计算 y(因为不论 y 为何值,“或”操作的结果都为 true)。这被称作为“短路”计算。
3. ^ 位异或 
 1) 运算规则 
位异或运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑异或运算。只有当对应位的二进制数互斥的时候,对应位的结果才为真。例如:int型常量5和7进行位异或运算的表达式为5^7,结果如下:5=0000 0000 0000 0101^7=0000 0000 0000 0111
= 0000 0000 0000 0010
2) 典型应用 
 (1)定位翻转 
定位翻转:设定一个数据的指定位,将1换为0,0换为1。例如整型数a=321,,将其低八位数据进行翻位的操作为a=a^0XFF;
(2)数值交换 
数值交换。例如a=3,b=4。在例11-1中,无须引入第三个变量,利用位运算即可实现数据交换。以下的操作可以实现a,b两个数据的交换:
a=a^b;
b=b^a;
a=a^b;
4.~ 位非 
位非运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑非运算。
 
二.位移运算符
1.位左移
左移运算的实质是将对应的数据的二进制值逐位左移若干位,并在空出的位置上填0,最高位溢出并舍弃。例如int a,b;
a=5;
b=a<<2;
则b=20,分析过程如下:
(a)10=(5)10=(0000 0000 0000 0101)2
b=a<<2;
b=(0000 0000 0001 0100)2=(20)10
从上例可以看出位运算可以实现二倍乘运算。由于位移操作的运算速度比乘法的运算速度高很多。因此在处理数据的乘法运算的时,采用位移运算可以获得较快的速度。
提示 将所有对2的乘法运算转换为位移运算,可提高程序的运行效率
2.位右移
位右移运算的实质是将对应的数据的二进制值逐位右移若干位,并舍弃出界的数字。如果当前的数为无符号数,高位补零。例如:
int (a)10=(5)10=(0000 0000 0000 0101)2
b=a>>2;
b=(0000 0000 0000 0001)2=(1)10
如果当前的数据为有符号数,在进行右移的时候,根据符号位决定左边补0还是补1。如果符号位为0,则左边补0;但是如果符号位为1,则根据不同的计算机系统,可能有不同的处理方式。可以看出位右移运算,可以实现对除数为2的整除运算。
提示 将所有对2的整除运算转换为位移运算,可提高程序的运行效率
3.复合的位运算符
在C语言中还提供复合的位运算符,如下:
&=、!=、>>=、<<=和^=
例如:a&=0x11等价于 a= a&0x11,其他运算符以此类推。
不同类型的整数数据在进行混合类型的位运算时,按右端对齐原则进行处理,按数据长度大的数据进行处理,将数据长度小的数据左端补0或1。例如char a与int b进行位运算的时候,按int 进行处理,char a转化为整型数据,并在左端补0。
补位原则如下:
1) 对于有符号数据:如果a为正整数,则左端补0,如果a 为负数,则左端补1。
2) 对于无符号数据:在左端补0。
4.例子
例11-2 获得一个无符号数据从第p位开始的n位二进制数据。假设数据右端对齐,第0位二进制数在数据的最右端,获得的结果要求右对齐。
#include
/*getbits:获得从第p位开始的n位二进制数 */
unsigned int getbits(unsigned int x, unsigned int p, unsigned n)
{
unsigned int a;
unsigned int b;
a=x>>(p+1);
b=~(~0<
return a&b;
}
提示 在某一平台进行程序开发时,首先要求了解此系统的基本数据类型的有效范围, 对涉及的位运算进行评估,特别是要对边界数据进行检测,确保计算正确。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值