位操作的技巧

原创 2015年07月06日 18:54:35

一,基本概念认知
1,为啥要用补码
计算机中的符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。(来自百度百科)
2,补码的求法:
正数的补码和原码相同;
负数是对应正数原码取反后加1;(或者现将对应正数减1,然后取反)
补码绝对值求法:对补码取反加1;
负数的补码如果一直向右移动一位(相当于/2),则会变成0xFFFFFFFF,形成死循环。因为每次移位负数的最高为都会补上1.。
3, 怎么表示相反数:
n=-n=~(n-1)=~n+1;正好对应了负数补码的求法;

二,位操作原理和技巧【x既可以表示一个正数,也适用于表示某一位的情况(0或者1)】微笑
1,异或:(三种状态)
x^0=x;(和0异或没有变化)
x^1=~x;(和1异或相当于取反)
x^x=0;(和自己异或相当于清0)
2,&(两种状态:清0或者不变)
x&0=0;(和0取&相当于清0)
x&1=x;(和1取&没有变化)
x&x=x;(和自己取&没有变化)
3,|(两种状态:置1或者不变)
x|0=x;(和0取|没有变化)
x|1=1;(和1取|相当于置1)
x|x=x;(和自己取|没有变化)
4,依据上面几点位操作的应用:
(1) 获取某一位的信息

bool getBit(int num,int i){
  return (num&(1<<i));
}

(2)置位(某一位置1,其他位不影响)

int setBit(int num,int i){
    return num|(1<<i);
 }

(3)清0(虽然异或可以做到,但是取&是最好的办法)
a)只将某一位清0,其他位不动;
利用&特性,和1取&不变,和0取&清0

int clearBit(int num,int i){//清0方法1,使用&
    int mask=~(1<<i);
    return num&mask;
 }

有人想到可以利用异或的特性,和0异或不变,和自己异或清0;但是这样的话,需要判断这一位是0还是1,比较麻烦。

b)将num最高位到i位(包含i位)清零:
和a)类似。把mask变一下。

int mask=(1<<i)-1;

c)将num的i位(含)到0位清零:
只写出mask

int mask=~((i<<(i+1))-1);

三,位操作实现加减乘除
3.0 工具栏
<1>获取整数n的二进制中最后一个1:n&(-n) 或者 n&~(n-1),如:n=010100,则-n=101100,n&(-n)=000100

<2>去掉整数n的二进制中最后一个1:n&(n-1),如:n=010100,n-1=010011,n&(n-1)=010000

例题:求二进制数中1的位数(编程之美)

int count(int num){//不断去除最后一个1,这个写法效率很高
  int res=0;
  while(num){//只循环了1的个数的次数
     num&=(num-1);
     res++;
  }
  return res;
 }

3.1 加运算
对于x和y两个数,如果他们相加过程中完全不需要进位的话,相加是不是就是很容易的事情了。就相当于x^y就OK了吧。
但是如果有进位的情况,就是有那么一个或多个bit,x和y在那一位上都是1。x&y就可以判断哪几位都是1。进位就是左移一位,就是(x&y)<<1;
所以x和y的相加,可以分为两部分:可以看做是不需要进位的那些位之和x^y,加上需要进位的部分之和(x&y)<<1。不断循环即可,直到没有进位。

int add(int x, int y){
    int add,carry;
    do{
        add=x^y;
        carry=(x&y)<<1;
        x=add;
        y=carry;
    }while(carry);
    return add;
}

3.2 减运算
x-y=x+(-y)=x+(~y+1);
int 的范围-2147483648(绝对值是2^31)--2147483647(2^31-1)

int subtract(int x,int y){
     return add(x,add(~y,1));
}

3.3 乘法运算
乘法的规律是什么呢。看这样的例子:2*7=14;
转换为二进制会看的明白:0010*0111=0010*(0001+0010+0100)=0010<<0+0010<<1+0010<<2=0010+0100+1000=1110;
这时候求出7的最后一位1的位置,然后再去掉最后一位1,如此循环到7变为0为止。
考虑溢出,如果大于INT_MAX 输出INT_MAX;如果小于INT_MIN,输出INT_MIN。

int multiply(int x,int y){
     map<unsigned int,int> bit_map;
     bool neg=(x<0)^(y<0);
     long long res=0;
     unsigned int x1=x>0?x:-x;
     unsigned int y1=y>0?y:-y;
     for(int i=0;i<32;i++){
        bit_map[1<<i]=i;
     }
     while(y){
        int lastBit=y1&(-y1);
        res+=x1<<bit_map[lastBit];
        if(res>INT_MAX) return neg==true?INT_MIN:INT_MAX;
        y1&=(y1-1);
     }
     if(neg) res=-res;
     return res;
}

3.4 除法运算
除法就是不断的减去一部分值,对应乘法的加。先减去最大的那个因子。也是根据因子的二进制,先找出因子的最高位,被除数减去这部分,然后找出次高位…直到被除数小于除数。

下面的代码,充分考虑了溢出的情况,针对有INT_MIN输入。如果结果大于INT_MAX,则输出INT_MAX;

int divide(int x,int y){
   assert(y!=0);//y不可以为0;
   bool neg=(x<0)^(y<0);
   unsigned int x1=x>0?x:-x;//防止INT_MIN的溢出
   unsigned int y1=y>0?y:-y;//防止INT_MIN的溢出
   long long pos=y1;//非常关键,防止溢出
   unsigned int res=0;
   int bit=0;
   for(;pos<=x1;bit++)
   {
       pos=pos<<1;
   }
   while(x1>=y1){
     if(x1>=pos){
        res|=1<<bit;
        x1-=pos;
     }else{
         pos>>=1;
         bit--;
     }
   }

   if(res>INT_MAX&&!neg) return INT_MAX;
   if(neg) res=-res;
   return (int)res;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

23个位运算技巧

20个位运算技巧 1.获得int型最大值 int getMaxInt(){ return (1
  • itismelzp
  • itismelzp
  • 2015年12月16日 13:53
  • 799

位操作技巧

检测一个无符号数是不为2^n-1(^为幂):   x&(x+1)         将最右侧0位改为1位:   x   |   (x+1)         二进制补码运算公式:     -x   =  ...
  • oncreate
  • oncreate
  • 2007年05月30日 12:17
  • 1011

一些位操作的技巧

计算二进制中1的个数 int CountOf1(int num) { int count=0; while(num) { ++count; num&=(num-1); } retu...
  • wjimin2008
  • wjimin2008
  • 2014年04月23日 14:51
  • 398

C之奇淫技巧——宏的妙用

一、指定的初始化 很多人都知道像这样来静态地初始化数组: int fibs[] = {1,2,3,4,5} ; C99标准实际上支持一种更为直观简单的方式来初始化各种不同的集合类数据(如:结构体,...
  • yang_yulei
  • yang_yulei
  • 2014年06月18日 08:39
  • 7273

ARM学习随笔(1) 位操作

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

位操作算法的总结(一)

本文参考《程序员面试金典》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
  • 633

C语言位操作技巧

一基本位操作符 & 位与       | 位或          ~ 位反        ^ 位异或     > 右移 (1)&: 参加运算的两个数据,按位进行与运算。如果两个相应的位都为1,...
  • HelloYaphetS
  • HelloYaphetS
  • 2012年07月06日 17:13
  • 287

BitHacks--位操作技巧

----------------------------------------------------------------------------------------------------...
  • luozhaowork
  • luozhaowork
  • 2013年08月26日 22:06
  • 860

位操作技巧实例大全

检测一个无符号数是不为2^n-1(^为幂): x&(x+1)将最右侧0位改为1位: x | (x+1)二进制补码运算公式:-x = ~x + 1 = ~(x-1)~x = -x-1 -(~x) = x...
  • sunyubo458
  • sunyubo458
  • 2009年07月24日 17:52
  • 362

位操作基础篇之常用位操作技巧

下面对位操作的一些常见应用作个总结,有判断奇偶、交换两数、变换符号及求绝对值。这些小技巧应用易记,应当熟练掌握。 1.判断奇偶 只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。...
  • bbewx
  • bbewx
  • 2014年04月27日 23:23
  • 308
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:位操作的技巧
举报原因:
原因补充:

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