檢測一個無符號數是不爲2^n-1(^爲冪): x&(x+1)
將最右側0位改爲1位: x | (x+1)
二進制補碼運算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)^((x^y)&((x-y)^x))
x<=y: (x|~y)&((x^y)|~(y-x))
x< y: (~x&y)|((~x|y)&(x-y))//無符號x,y比較
x<=y: (~x|y)&((x^y)|~(y-x))//無符號x,y比較
使用位運算的無分支代碼:
計算絕對值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ;//or: (x+y)^y
}
符號函數:sign(x) = -1, x<0; 0, x == 0 ; 1, x > 0
int sign(int x)
{
return (x>>31) | (unsigned(-x))>>31 ;//x=-2^31時失敗(^爲冪)
}
三值比較:cmp(x,y) = -1, x<y; 0, x==y; 1, x > y
int cmp( int x, int y )
{
return (x>y)-(x-y) ;
}
doz=x-y, x>=y; 0, x<y
int doz(int x, int y )
{
int d ;
d = x-y ;
return d & ((~(d^((x^y)&(d^x))))>>31) ;
}
int max(int x, int y )
{
int m ;
m = (x-y)>>31 ;
return y & m | x & ~m ;
}
不使用第三方交換x,y:
1.x ^= y ; y ^= x ; x ^= y ;
2.x = x+y ; y = x-y ; x = x-y ;
3.x = x-y ; y = y+x ; x = y-x ;
4.x = y-x ; x = y-x ; x = x+y ;
雙值交換:x = a, x==b; b, x==a//常規編碼爲x = x==a ? b :a ;
1.x = a+b-x ;
2.x = a^b^x ;
下舍入到2的k次方的倍數:
1.x & ((-1)<<k)
2.(((unsigned)x)>>k)<<k
上舍入:
1. t = (1<<k)-1 ; x = (x+t)&~t ;
2.t = (-1)<<k ; x = (x-t-1)&t ;
位計數,統計1位的數量:
1.
int pop(unsigned x)
{
x = x-((x>>1)&0x55555555) ;
x = (x&0x33333333) + ((x>>2) & 0x33333333 ) ;
x = (x+(x>>4)) & 0x0f0f0f0f ;
x = x + (x>>8) ;
x = x + (x>>16) ;
return x & 0x0000003f ;
}
2.
int pop(unsigned x) {
static char table[256] = { 0,1,1,2, 1,2,2,3, ...., 6,7,7,8 } ;
return table[x&0xff]+table[(x>>8)&0xff]+table[(x>>16)&0xff]+table[(x>>24)] ;
}
3.求下面函數的返回值(microsoft)
int func(x)
{
int countx = 0;
while(x)
{
countx++;
x = x&(x-1);
}
return countx;
}
這個函數的功能就是返回數中1的個數。
假定x = 9999。 答案:8
思路:將x轉化爲2進制,看含有的1的個數。
用最簡單的方法判斷一個LONG整形的數A是2^n
答案:(n-1)&n
奇偶性計算:
x = x ^ ( x>>1 ) ;
x = x ^ ( x>>2 ) ;
x = x ^ ( x>>4 ) ;
x = x ^ ( x>>8 ) ;
x = x ^ ( x>>16 ) ;
結果中位於x最低位,對無符號x,結果的第i位是原數第i位到最左側位的奇偶性
位反轉:
unsigned rev(unsigned x)
{
x = (x & 0x55555555) << 1 | (x>>1) & 0x55555555 ;
x = (x & 0x33333333) << 2 | (x>>2) & 0x33333333 ;
x = (x & 0x0f0f0f0f) << 4 | (x>>4) & 0x0f0f0f0f ;
x = (x<<24) | ((x&0xff00)<<8) | ((x>>8) & 0xff00) | (x>>24) ;
return x ;
}
遞增位反轉後的數:
unsigned inc_r(unsigned x)
{
unsigned m = 0x80000000 ;
x ^= m ;
if( (int)x >= 0 )
do { m >>= 1 ; x ^= m ; } while( x < m ) ;
return x ;
}
混選位:
abcd efgh ijkl mnop ABCD EFGH IJKL MNOP->aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP
unsigned ps(unsigned x)
{
unsigned t ;
t = (x ^ (x>>8)) & 0x0000ff00; x = x ^ t ^ (t<<8) ;
t = (x ^ (x>>4)) & 0x00f000f0; x = x ^ t ^ (t<<4) ;
t = (x ^ (x>>2)) & 0x0c0c0c0c; x = x ^ t ^ (t<<2) ;
t = (x ^ (x>>1)) & 0x22222222; x = x ^ t ^ (t<<1) ;
return x ;
}
位壓縮:
選擇並右移字x中對應於掩碼m的1位的位,如:compress(abcdefgh,01010101)=0000bdfh
compress_left(x,m)操作與此類似,但結果位在左邊: bdfh0000.
unsigned compress(unsigned x, unsigned m)
{
unsigned mk, mp, mv, t ;
int i ;
x &= m ;
mk = ~m << 1 ;
for( i = 0 ; i < 5 ; ++i ) {
mp = mk ^ ( mk << 1) ;
mp ^= ( mp << 2 ) ;
mp ^= ( mp << 4 ) ;
mp ^= ( mp << 8 ) ;
mp ^= ( mp << 16 ) ;
mv = mp & m ;
m = m ^ mv | (mv >> (1<<i) ) ;
t = x & mv ;
x = x ^ t | ( t >> ( 1<<i) ) ;
mk = mk & ~mp ;
}
return x ;
}
位置換:
用32個5位數表示從最低位開始的位的目標位置,結果是一個32*5的位矩陣,
將該矩陣沿次對角線轉置後用5個32位字p[5]存放。
SAG(x,m) = compress_left(x,m) | compress(x,~m) ;
準備工作:
void init( unsigned *p ) {
p[1] = SAG( p[1], p[0] ) ;
p[2] = SAG( SAG( p[2], p[0]), p[1] ) ;
p[3] = SAG( SAG( SAG( p[3], p[0] ), p[1]), p[2] ) ;
p[4] = SAG( SAG( SAG( SAG( p[4], p[0] ), p[1]) ,p[2]), p[3] ) ;
}
實際置換:
int rep( unsigned x ) {
x = SAG(x,p[0]);
x = SAG(x,p[1]);
x = SAG(x,p[2]);
x = SAG(x,p[3]);
x = SAG(x,p[4]);
return x ;
}
二進制碼到GRAY碼的轉換:
unsigned B2G(unsigned B )
{
return B ^ (B>>1) ;
}
GRAY碼到二進制碼:
unsigned G2B(unsigned G)
{
unsigned B ;
B = G ^ (G>>1) ;
B = G ^ (G>>2) ;
B = G ^ (G>>4) ;
B = G ^ (G>>8) ;
B = G ^ (G>>16) ;
return B ;
}
找出最左0字節的位置:
int zbytel( unsigned x )
{
static cahr table[16] = { 4,3,2,2, 1,1,1,1, 0,0,0,0, 0,0,0,0 } ;
unsigned y ;
y = (x&0x7f7f7f7f) + 0x7f7f7f7f ;
y = ~(y|x|0x7f7f7f7f) ;
return table[y*0x00204081 >> 28] ;//乘法可用移位和加完成
}
//C++位操作運算符程序實例
#include <iostream.h>
void main()
{
unsigned int a(0x2a),b(18);
a&=b;
cout<<a<<endl;
a^=a;
cout<<a<<endl;
int i(-8),j(2);
i>>=j; //////分析1
cout<<i<<endl;
i|=~j^j; //////分析2
cout<<i<<','<<j<<endl;
j&=~i+1;;
cout<<i<<','<<j<<endl;
}
運行結果如下:
2
0
-2
-1,2
-1,0
分析1:
i>>=j; ///////意爲對i(-8)進行右移位j(2)位,然後賦值給i.
-8的原碼:10000000 00000000 00000000 00001000(按位取反,得反碼)
-8的反碼:11111111 11111111 11111111 11110111(加1,得補碼)
-8的補碼:11111111 11111111 11111111 11111111
右移兩位,移出去的空格全補符號位1,得
結果的補碼:11111111 11111111 11111111 11111110(減1得反碼)
結果的反碼:11111111 11111111 11111111 11111101(按位求反,得原碼)
結果的原碼:10000000 00000000 00000000 00000010(換成十進制:-2)
分析2:
i|=~j^j;
優先級高->低排:~,^,|=
先計算(~j)^j:11111111 11111111 11111111 11111111
然後:i=i|全1
得i=11111111 11111111 11111111 11111111(減1得反碼)
11111111 11111111 11111111 11111110(按位求反得原碼)
10000000 00000000 00000000 00000001(換成十進制:-1)
3./*
* minusOne - return a value of -1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 2
* Rating: 1
*/
int minusOne(void) {
/* In memory, -1 is represented as all 1 at every bit, so we got ~0*/
return ~0;
}
/*
* TMax - return maximum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmax(void) {
/*
* The largest positive integer is 01111111111111111111111111111111,
* it's two's complement is 1000000000000000000000000000000
*/
return ~(1<<31);
}
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 2
*/
int bitXor(int x, int y) {
/*
* Use x&y to find both 1 and ~x&~y to find both 0,the result of them at corresponding bit
* will be 1. ~(result1|result2) is the final result we want. Bring them into the bitOr above,
* we got ~(x&y)&~(~x&~y)
*/
return ~(x&y)&~(~x&~y);
}
/*
* getByte - Extract byte n from word x
* Bytes numbered from 0 (LSB) to 3 (MSB)
* Examples: getByte(0x12345678,1) = 0x56
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 6
* Rating: 2
*/
int getByte(int x, int n) {
/* Right shift x and makes higher part zero. n<<3 bits to shift */
return (x>>(n<<3))&(0x000000FF);
}
/*
* isEqual - return 1 if x == y, and 0 otherwise
* Examples: isEqual(5,5) = 1, isEqual(4,5) = 0
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int isEqual(int x, int y) {
/* If x is equal to y , every bit of x^y will be 0, !0 will be 1 */
return !(x^y);
}
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
/* This is just the way how to transform a positive to a nagative */
return ~x+1;
}
/*
* isPositive - return 1 if x > 0, return 0 otherwise
* Example: isPositive(-1) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 3
*/
int isPositive(int x) {
/*
* Use x>>31 to get the sign bit, when x is positve ~(x>>31) is 1, else it's 0.
* !x to verify whether x is 0, if it's 0, !x will be 1, and !!x will be 0.
* So if x is zero, it will return 0, and if x is not zero, it will return the first part.
* That's what we want
*/
return ~(x>>31)&(!!x);
}
4.下面這兩個程序是有關位的封裝的類:(是C++標準委員會的主席寫的)
//BitBuffer是由vector<unsigned char>來實現的
a. class BitBuffer{
public:
BitBuffer():buf_(0),size(0){}
//添加p所指的位緩衝區頭部的num個位
void Append(unsigned char* p, size_t num){
int bits = numeric_limits<unsigned char>::digit;//這是得到unsigned char的位數
//第一個目標字節和該字節中的位偏移
int dst = size_/bits;
int off = size_%bits;
while(buf_.size() < (size_+num)/bits + 1;
buf_.push_back(0);//鑑於下面的算法,這裏的push_back必須爲0
for(int i = 0; i < (num+bits-1)/bits; ++i){
unsigned char mask = FirstBits(num – bits*i);
buf_[dst+i] |= (*(p+i) & mask) >> off;//把當前字節的前bits-off位寫入目 標字節剩下的bits-off位空間中
if( off > 0)
buf_[dst+i+1] = (*(p+i) & mask) <<(bits – off);//把當前字節的後off位寫入目標字節下一字節的前off個空位中。
}
size_+=num;
}
//查詢正被使用的位數目(初始爲0)
size_t Size() const{
return size_;
}
//從第start位(位的編號從0開始)開始獲取num個位,並將結果存入dst所指的緩衝區(從緩衝區的第一位開始存放)
//dst所指的緩衝區除了能放下num位之外至少還要出一個字節。
void Get(size_t start, size_t num, unsigned char* dst)const{
int bits = numeric_limits<unsigned char>::digits;
//第一個目標字節和該字節中的位偏移
int src = start/bits;
int off = start%bits;
for(int i=0; i<(num+bits-1)/bits; ++i){
*(dst+i) = buf_[src+i] << off;
if(off > 0)
*(dst+i) |= buf_[src+i+1] >> (bits –off);//這個地方很巧
}
}
private:
vector<unsigned char> buf_;
size_t size_;
//創建一個前n位爲1,剩餘位爲0的掩碼。
unsigned char FirstBits(size_t n){
int num = min(n, numeric_limits<unsigned char>::digits;
unsigned char b = 0;
while(num-- > 0)
b = (b >> 1) | (1 << (numeric_limits<unsigned char>::digits-1));
return b;
}
};
b.class BitBuffer{
public:
//添加p所指的位緩衝區頭部的num個位
void Append(unsigned char* p, size_t num){
int bits = numeric_limits<unsigned char>::digit;//這是得到unsigned char的位數
for(int i= 0; i<num; ++i){
buf_.push_back(*p & ( 1<< (bits-1-i%bits)));
if((i+1) % bits == 0)
++p;
}
}
//查詢正被使用的位數目(初始爲0)
size_t Size() const{
return size_;
}
//從第start位(位的編號從0開始)開始獲取num個位,並將結果存入dst所指的緩衝區(從緩衝區的第一位開始存放)
void Get(size_t start, size_t num, unsigned char* dst)const{
int bits = numeric_limits<unsigned char>::digits;
*dst = 0;
for(int i = 0; i < num; ++i){
*dst |= unsigned char(buf_[start+i]) << (bits-1-i%bits);
if((i+1)%bits == 0)
*++dst = 0;
}
}
private:
vector<bool> buf_;
};