位操作整理

转载 2013年12月05日 15:49:38

整理一下位操作,便于自己以后查看。例子全部来源于网络,不能一一指出出处,见谅!注意:以下的例子都是一个具体的题目,有很多的时候并不意味着像下面那样做得到的代码更加高效,应该具体问题具体分析。

1.异或操作

定义:

异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。运算法则为:a⊕b = (¬a ∧ b) ∨ (a ∧¬b).

0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0。同0异1.与其它语言不同,C语言和C++语言的异或不用xor,而是“^”,其他语言的"^"多表示乘方。

运算法则

(1).a ⊕ b = b ⊕ a;//交换率

(2)a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c;//结合率

异或的特性:

(1).0异或任何数=任何数.a=0000,b=1011.a^b=1011,按位异或。

(2).a^a=0.

(3)a^b^a=b.

异或的一些例子:

(1)不引入第三个参数实现两个数的交换:

a=9=1001,b=11=1011.

a=a^b:1001^1011=0010

b=b^a;1011^0010=1001

a=a^b:0010^1001=1011

a=11,b=9.和a=a+b;b=a-b;a=a-b;有点像,位个人觉得就是用了异或特性的第三条。

(2)一个整数数组,除其中某一个元素只出现一次外,其他元素都出现了两次。求这个元素。

运用特性(3)代码如下:

int result=0;

for(int i=0;i<size;++i)

{

      result^=num[i];

}

cout<<result;

(3)接上面的那个题,一个整数数组中,除了两个元素只出现一次外,其他的都出现了两次。求这两个元素。

假设这两个元素是a和b,那么按照上面的处理result=a^b;假设a=9,b=11.那么result=0010,那么也就说a和b第三位不同,否则就会为0.那么我们现在把原数组的数按第三位分为两组:0组和1组。则a和b肯定不属于同一组。取某一组的数那么这组数一定是这样的:有a或者b,剩下的数都出现两次。让result的和这组数中所有的进行异或,便可以得到a或者b了。这个方法个人感觉只是提供了一种思路,并不一定是最好的,看题目有没有别的限制。

2.与操作

与操作的法则:1&0=0,1&1=1,0&0=0。全1和一个数求与还是那个数,全0和一个数求与就是置0.

3.或操作

或操作的法则:1|0=1,1|1=1,0|0=0.全0和一个数求或还是那个数,全1和一个数求或就是将那个数置为全1.

位操作的一些综合应用:

(1).用位操作求一个正整数除以7的余数。负整数我还没有试验过,先规定是正整数。

假设这个正整数是a,令x=a>>3,y=a&0x7,即a=(7+1)*x+y,如果x+y>7接着上面的做法做,直到得到的余数小于7为止。除以其他非2的次幂的思路都差不多。

(2).用位操作实现加法.

首先:异或操作相当于两个二进制相加但是没有进位的结果。与操作相当于求两个二进制数相加哪一位会有进位。

int add(int a,int b)
{
   int x=a&b;//进位
   int y=a^b;//未考虑进位得到的结果
   int t_x,t_y;//临时变量
   while(x)
   {
      t_x=x<<1;//进位的结果
      t_y=t;
      //将进位的结果加到y中
      x=t_x&t_y;
      y=t_x^t_y;
   }
}

(3)判断一个无符号的数是不是2的正整数次幂。

这个问题可以这么考虑:假设这个无符号的数为a,看a&(a-1)的结果,如果a是2的正整数次幂,那么结果应该是0,否则就不为0.

#include <iostream>
using namespace std;
int main()
{
   unsigned int a;
   cin>>a;
   int result=a&(a-1);
   if(result)
      cout<<"no"<<endl;
      else
	 cout<<"yes"<<endl;
}
这个问题可以进行一下拓展,就是判断一个无符号的正数(还是规定不为0吧,不然减掉1之后不知道表示什么了。)的二进制表示中有多少个1.代码如下:

#include <iostream>
using namespace std;
int main()
{
   unsigned int a;
   cin>>a;
   int count=0;
   while(a)
   {
      count++;
      a&=(a-1);
   }
   cout<<count<<std::endl;
   return 0;
}
实际每一次做&操作就去掉a中的一个1.
(4).求int的绝对值,int是32位的。

#include <iostream>
using namespace std;
int main()
{
   int x;
   cin>>x;
   int y=x>>31;
   cout<<y<<endl;
   cout<<(x^y)-y<<endl;
}
理解这段代码,需要好好理解计算机中补码移位的规则。

(5)将一个整数取反,如-8变成8,8变-8.8变-8在计算机中就是连同符号位在内所有位取反然后加1,所有位取反的方法就是和-1做异或。代码如下:

#include <iostream>
using namespace std;
int main()
{
   int a,result;
   cin>>a;
   result=(a^(-1))+1;
   cout<<result<<endl;
   return 0;
}

(6)高低位交换:给出一个16位的无符号整数。称这个二进制数的前八位为“高位“,后八位为”低位“。现在写一个程序把这个二进制的数的高低位交换。例如;10000110 11011000变成11011000 10000110设x=34520=10000110 11011000(二进制) 由于x为无符号数,右移时会执行逻辑右移即高位补0,因此x右移8位将得到0000000010000110。而x左移8位将得到11011000 00000000。可以发现只要将x>>8与x<<8这两个数相或就可以得到11011000 10000110。如果是有符号的数,那就要弄清楚补码的移位规则了。

(7)接上一个问题,二进制的逆续。第一步我们可以把这个二进制的数以两位为一组分成若干组,组内高低位交换。第二步以四位一组分成若干组,组内高低位交换,类推。代码如下:

#include <iostream>
using namespace std;
void display(int a)
{
   int stack[32]={0};
   int top=0;
   while(a>0)
   {
	  stack[top++]=a%2;
	  a/=2;
   }
   for(int i=31;i>=0;--i)
   {
	  cout<<stack[i];
   }
   cout<<endl;
}
int main()
{
   int a;
   cin>>a;
   cout<<"before reverse"<<endl;
   display(a);
   cout<<"after reverse"<<endl;
   a=((a>>1)&0x55555555)|((a<<1)&0xAAAAAAAA);
   a=((a>>2)&0x33333333)|((a<<2)&0xCCCCCCCC);
   a=((a>>4)&0x0F0F0F0F)|((a<<4)&0xF0F0F0F0);
   a=((a>>8)&0x00FF00FF)|((a<<8)&0xFF00FF00);
   display(a);
}
我这里输出二进制的时候是以32位做标准的,前面添0了。

位操作算法面试题

位操作算法面试题,包含详细解析
  • sunxianghuang
  • sunxianghuang
  • 2016年07月31日 19:56
  • 987

【IT笔试面试题整理】位操作

如何准备: Bit manipulation can be a scary thing to many candidates, but it doesn’t need to be! If you’re...
  • zwqjoy
  • zwqjoy
  • 2017年12月15日 14:35
  • 43

一些位操作函数

 转自http://www.hseda.com/mcu/cbitop.htm#define uchar unsigned char/*测试变量某一位是否为‘1’,是返回真,否返回假,num为待测试的数...
  • bingyan123456
  • bingyan123456
  • 2006年03月31日 20:58
  • 595

位操作算法的总结(一)

本文参考《程序员面试金典》1.位操作原理与技巧第一组:-x^000..000 = x ; - x^111..111 = ~x; - x^x = 0;第二组: x&000..000 = 0; x&1...
  • qq_16811963
  • qq_16811963
  • 2016年08月16日 22:47
  • 629

sqlserver数据库中的位操作功能

sqlserver数据库中的位操作功能很少。开发以下功能,补充其应用。望能对大家有帮助。...
  • cuckoo1
  • cuckoo1
  • 2016年03月24日 16:33
  • 786

ARM学习随笔(1) 位操作

由于刚开始学习ARM,看到很多
  • bgk083
  • bgk083
  • 2014年07月19日 13:23
  • 398

java中的位操作

public class Test { public static void main(String[] args) { // 1、正数左移(
  • github_36268254
  • github_36268254
  • 2017年02月05日 19:37
  • 167

C# 中的位操作

位操作符是对数据按二进制位进行运算的操作符。c#位操作符包括:按位与 & 按位或 | 按位取反 ~ 左移 右移 >> 举例说明using System; class MikeCat {   publi...
  • daonidedie
  • daonidedie
  • 2014年04月03日 13:41
  • 1497

c语言-编程位操作技巧

http://www.acmwiki.com/index.php?doc-view-5.htm  位反转:  unsigned rev(unsigned x)  {      ...
  • hengfanz
  • hengfanz
  • 2014年04月16日 17:38
  • 852

stm32位操作函数(未完待续)

stm32位操作函数 昨天看到了普中科技的数码管操作函数,对stm32的位操作函数,自己也不太懂,就查了一下,现在整理学习笔记如下: 主要学习到了stm32操作函数的两个位操作函数,现在我们用寄存器和...
  • zhanghuaichao
  • zhanghuaichao
  • 2015年11月22日 12:46
  • 1017
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:位操作整理
举报原因:
原因补充:

(最多只允许输入30个字)