最近看了一篇文章<
原文地址:http://graphics.stanford.edu/~seander/bithacks.html#OperationCounting
1、Compute the sign of an integer
// we want to find the sign of v
int v;
// the result goes here
int sign;
// CHAR_BIT is the number of bits per byte (normally 8).
// if v < 0 then -1, else 0.
sign = -(v < 0);
// or, to avoid branching on CPUs with flag registers (IA32):
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1);
// if v < 0 then -1, else +1
sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1));
// if v < 0 then -1, else if v > 0 then 1, else 0
sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// Or, for more speed but less portability:
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1));
// Or, for portability, brevity, and (perhaps) speed:
sign = (v > 0) - (v < 0);
// if v >= 0 then 1, else 0
sign = 1 ^ ((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1));
// input values to compare signs
int x, y;
// true if x and y have opposite signs
bool f = ((x ^ y) < 0);
// we want to find the absolute value of v
int v;
// the result goes here
unsigned int r;
// if v >= 0 then 0, else -1
const int mask = v >> (sizeof(int) * CHAR_BIT - 1);
// general method
r = (v < 0) ? -(unsigned int)v : v;
// if v >= 0 then r = (v + 0) ^ 0
// if v < 0 then r = (v + (-1)) ^ (-1)
r = (v + mask) ^ mask;
// patented variation
// if v < 0 then r = (v ^ (-1)) + 1
r = (v ^ mask) - mask;
// we want to find the minimum of x and y
int x;
int y;
// the result goes here
int r;
// min(x, y)
r = y ^ ((x ^ y) & -(x < y));
// max(x, y)
r = x ^ ((x ^ y) & -(x < y));
// quick and dirty versions
// if INT_MIN <= x - y <= INT_MAX
// min(x, y)
r = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1)));
// max(x, y)
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1)));
// we want to see if v is a power of 2
unsigned int v ;
// the result goes here
bool f;
// include 0, but 0 is incorrect
f = (v & (v - 1)) == 0;
// not include 0
f = v && !(v & (v - 1));
In C, sign extension from a constant bit-width is trival, since bit fields may be specified in structs or unions. For example, to convert from 5 bits to an full integer.
int x;
int r;
struct { signed int x:5; } s;
r = s.x = x;
template
inline T signextend(const T x) {
struct { signed int x:B; } s;
return s.x = x;
}
int r = signextend(x);
7、 Counting bits set
unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; v >>= 1) {
c += v & 1;
}
unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++) {
v &= v - 1; // clear the least significant bit set
}
Counting bits set in 14, 24, or 32-bit words using 64-bit instructions
Counting bits set, in parallel
Count bits set (rank) from the most-significant bit upto a given position
Select the bit position(from the most-significant bit) with the given count(rank)
上面这些看上去很复杂的样子,头大了,先跳过吧。
9、 Computing parity the naive way
unsigned int v; // word value to compute the parity of
bool parity = false; // parity will be the parity of v
while (v) {
parity = !parity;
v = v & (v - 1);
}
static const bool ParityTable256[256] =
{
# define P2(n) n, n^1, n^1, n
# define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
# define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
P6(0), P6(1), P6(1), P6(0)
};
unsigned char b; // byte value to compute the parity of
bool parity = ParityTable256[b];
// OR, for 32-bit words:
unsigned int v;
v ^= v >> 16;
v ^= v >> 8;
bool parity = ParityTable256[v & 0xff];
// Variation:
unsigned char * p = (unsigned char *) &v;
parity = ParityTable256[p[0] ^ p[1] ^ p[2] ^ p[3]];
unsigned char b; // byte value to compute the parity of
bool parity =
(((b * 0x0101010101010101ULL) & 0x8040201008040201ULL) % 0x1FF) & 1;
The following method computers the parity of the 32-bit value in only 8 operations using a multiply.
unsigned int v; // 32-bit word
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111U) * 0x11111111U;
return (v >> 28) & 1;
unsigned long long v; // 64-bit word
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x1111111111111111UL) * 0x1111111111111111UL;
return (v >> 60) & 1;
unsigned int v; // word value to compute the parity of
v ^= v >> 16;
v ^= v >> 8;
v ^= v >> 4;
v &= 0xf;
return (0x6996 >> v) & 1;
#define SWAP(a, b) ((&(a) == &(b)) || \
(((a) -= (b)), ((b) += (a)), ((a) = (b) - (a))))
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
// positions of bit sequences to swap
unsigned int i, j;
// number of consecutive bits in each sequence
unsigned int n;
// bits to swap reside in b
unsigned int b;
// bit-swapped result goes here
unsigned int r;
// XOR temporary
unsigned int x = ((b >> i) ^ (b >> j)) & ((1U << n) - 1);
r = b ^ ((x << i) | (x << j));
As an example of swapping ranges of bits suppose we have have b = 00101111 (expressed in binary) and we want to swap the n = 3 consecutive bits starting at i = 1 (the second bit from the right) with the 3 consecutive bits starting at j = 5; the result would be r = 11100011 (binary).
This method of swapping is similar to the general purpose XOR swap trick, but intended for operating on individual bits. The variable x stores the result of XORing the pairs of bit values we want to swap, and then the bits are set to the result of themselves XORed with x. Of course, the result is undefined if the sequences overlap.
17、Reverse bits the obvious way
unsigned int v;
// get the last bit of v
unsigned int r = v;
int s = sizeof(v) * CHAR_BIT - 1;
for(v >>= 1; v; v >>= 1) {
r <<= 1;
r |= (v&1);
s--;
}
// the lead zero
r <<= s;
unsigned int v;
// the inital val of f is 0
unsigned int r = 0;
// the total bits of v
int s = sizeof(v) * CHAR_BIT;
for( ; v; v >>= 1) {
r <<= 1;
r |= (v & 1);
s--;
}
// the lead zero
r <<= s;
直接贴作者的代码了...
static const unsigned char BitReverseTable256[256] =
{
# define R2(n) n, n + 2*64, n + 1*64, n + 3*64
# define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
# define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
R6(0), R6(2), R6(1), R6(3)
};
unsigned int v; // reverse 32-bit value, 8 bits at time
unsigned int c; // c will get v reversed
// Option 1:
c = (BitReverseTable256[v & 0xff] << 24) |
(BitReverseTable256[(v >> 8) & 0xff] << 16) |
(BitReverseTable256[(v >> 16) & 0xff] << 8) |
(BitReverseTable256[(v >> 24) & 0xff]);
// Option 2:
unsigned char * p = (unsigned char *) &v;
unsigned char * q = (unsigned char *) &c;
q[3] = BitReverseTable256[p[0]];
q[2] = BitReverseTable256[p[1]];
q[1] = BitReverseTable256[p[2]];
q[0] = BitReverseTable256[p[3]];
const unsigned int n; // numerator
const unsigned int s;
const unsigned int d = 1U << s; // So d will be one of: 1, 2, 4, 8, 16, 32, ...
unsigned int m; // m will be n % d
m = n & (d - 1);
unsigned int n; // numerator
const unsigned int s; // s > 0
const unsigned int d = (1 << s) - 1;// so d is either 1, 3, 7, 15, 31, ....
unsigned int m; // n % d goes here
for(m = n; n > d; n = m) {
for(m = 0; n; n >>= s) {
m += n & d;
}
}
// Now m is a value from 0 to d, but since with modulus division
// we want m to be 0 when it is d
m = m == d ? 0 : m;
// 32-bit word to find the log base 2 of
unsigned int v;
// r will be lg(v)
unsigned int r = 0;
while(v >>= 1) {
++r;
}
// input to count trailing zero bits
unsigned int v;
// output: c will count v's trailing zero bits
// so if v is 1101000(base 2), then c will be 3
int c;
if(v) {
v = (v ^ (v - 1)) >> 1;
for(c = 0; v; v >>= 1, ++c);
/*
for(c = 0; v; ++c) {
v >>= 1;
}
*/
} else {
c = sizeof(v) * CHAR_BIT;
}
// 32-bit word input to count zero bits on right
unsigned int v;
// c will be the number of zero bits on the right
// so if v is 1101000(base 2), then c will be 3
unsigned int c;
// NOTE : if 0 == v, then c = 31
if(v & 0x1) {
// special case for odd v (assumed to happen half of the time)
c = 0;
} else {
c = 1;
if((v & 0xffff) == 0) {
v >>= 16;
c += 16;
}
if((v & 0xff) == 0) {
v >>= 8;
c += 8;
}
if((v & 0xf) == 0) {
v >>= 4;
c += 4;
}
if((v & 0x3) == 0) {
v >>= 2;
c += 2;
}
c -= v & 0x1;
}
unsigned short x; // Interleave bits of x and y, so that all of the
unsigned short y; // bits of x are in the even positions and y in the odd;
unsigned int z = 0; // z gets the resulting Morton Number.
for (int i = 0; i < sizeof(x) * CHAR_BIT; i++) // unroll for more speed...
{
z |= (x & 1U << i) << i | (y & 1U << i) << (i + 1);
}
Interleaved bits (aka Morton numbers) are useful for linearizing 2D integer coordinates, so x and y are combined into a single number that can be compared easily and has the property that a number is usually close to another if their x and y values are close.
25、 Compute the lexicographically next bit permutation
Suppose we have a pattern of N bits set to 1 in an integer and we want the next permutation of N 1 bits in a lexicographical sense. For example, if N is 3 and the bit pattern is 00010011, the next patterns would be 00010101, 00010110, 00011001,00011010, 00011100, 00100011, and so forth. The following is a fast way to compute the next permutation.
unsigned int v; // current permutation of bits
unsigned int w; // next permutation of bits
unsigned int t = v | (v - 1); // t gets v's least significant 0 bits set to 1
// Next set to 1 the most significant bit to change,
// set to 0 the least significant ones, and add the necessary 1 bits.
w = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));
The __builtin_ctz(v) GNU C compiler intrinsic for x86 CPUs returns the number of trailing zeros. If you are using Microsoft compilers for x86, the intrinsic is _BitScanForward. These both emit a bsf instruction, but equivalents may be available for other architectures. If not, then consider using one of the methods for counting the consecutive zero bits mentioned earlier.
更多内容参照原文,我只是把我能理解的代码摘了下来,更多神奇的代码请看原文。