开发人员应该知道哪些有用的按位运算符代码技巧?
我必须说我从来没有理由使用按位运算符,但是我确信有一些我已经执行的操作可以更有效地完成它们。 如何“转移”和“OR-ing”帮助您更有效地解决问题?
看到着名的Bit Twiddling Hacks
大多数乘法/除法运算是不必要的 – 编译器会自动执行这些操作,只会让人们感到困惑。
但是,如果使用硬件或通信协议,则会有一堆“检查/设置/切换位N”types的黑客。
对string(字符)使用按位操作
将字母转换为小写 :
-
OR
by space =>(x | ' ')
- 结果总是小写,即使信件已经是小写字母
- 例如。
('a' | ' ') => 'a'
;('A' | ' ') => 'a'
将字母转换为大写字母 :
-
AND
by underline =>(x & '_')
- 即使字母已经是大写,结果总是大写
- 例如。
('a' & '_') => 'A'
;('A' & '_') => 'A'
反转信的情况:
-
XOR
by space =>(x ^ ' ')
- 例如。
('a' ^ ' ') => 'A'
;('A' ^ ' ') => 'a'
字母在字母表中的位置 :
-
AND
bychr(31)
/binary('11111')
/(hex('1F')
=>(x & "\x1F")
- 结果在1..26的范围内,字母大小写不重要
- 例如。
('a' & "\x1F") => 1
;('B' & "\x1F") => 2
获取字母的字母位置 (仅限大写字母):
-
AND
?
=>(x & '?')
或XOR
by@
=>(x ^ '@')
- 例如。
('C' & '?') => 3
;('Z' ^ '@') => 26
获取字母的位置 (仅限小写字母):
-
XOR
by backtick /chr(96)
/binary('1100000')
/hex('60')
=>(x ^ '`')
- 例如。
('d' ^ '`') => 4
;('x' ^ '`') => 25
注意:使用英文字母以外的任何东西都会产生垃圾结果
- 整数上的按位运算(int)
获取最大整数
int maxInt = ~(1 << 31); int maxInt = (1 << 31) - 1; int maxInt = (1 << -1) - 1;
获取最小整数
int minInt = 1 << 31; int minInt = 1 << -1;
获得最长的时间
long maxLong = ((long)1 << 127) - 1;
乘以2
n << 1; // n*2
除以2
n >> 1; // n/2
乘以2的m次幂
n << m;
除以2的m次方
n >> m;
检查奇数
(n & 1) == 1;
交换两个值
a ^= b; b ^= a; a ^= b;
获得绝对的价值
(n ^ (n >> 31)) - (n >> 31);
获取两个值的最大值
b & ((ab) >> 31) | a & (~(ab) >> 31);
获取两个值的最小值
a & ((ab) >> 31) | b & (~(ab) >> 31);
检查两者是否有相同的标志
(x ^ y) >= 0;
计算2 ^ n
2 << (n-1);
是否是2的阶乘
n > 0 ? (n & (n - 1)) == 0 : false;
模2 ^ n对m
m & (n - 1);
得到平均水平
(x + y) >> 1; ((x ^ y) >> 1) + (x & y);
得到n的第m位(从低到高)
(n >> (m-1)) & 1;
将n的第m位设置为0(从低到高)
n & ~(1 << (m-1));
n + 1
-~n
n – 1
~-n
获取对比数字
~n + 1; (n ^ -1) + 1;
if(x == a)x = b; if(x == b)x = a;
x = a ^ b ^ x;
我用过的频率只有三个:
-
设置一下:a | = 1 << bit;
-
清除一下:a&=〜(1 << bit);
-
testing一下位:a&(1 << bit);
Matters Computational:Ideas,Algorithms,Source Code,by Jorg Arndt(PDF) 。 这本书包含了大量的东西,我通过http://www.hackersdelight.org/上的链接find它。;
平均没有溢出
计算两个参数x和y的平均值(x + y)/ 2的例程是
static inline ulong average(ulong x, ulong y) // Return floor( (x+y)/2 ) // Use: x+y == ((x&y)<<1) + (x^y) // that is: sum == carries + sum_without_carries { return (x & y) + ((x ^ y) >> 1); }
你可以压缩数据,例如整数集合:
- 查看集合中哪些整数值更频繁地出现
- 使用短位序列来表示更频繁出现的值 (以及更长的位序列来表示出现频率较低的值)
- 连接比特序列:例如,结果比特stream中的前3个比特可能代表一个整数,接下来的9比特代表另一个整数等等。
计数设置位,find最低/最高设置位,find第n个从顶部/底部设置位和其他可以是有用的,这是值得看的位twiddling黑客站点。
也就是说,这种事情不是日常重要的。 有用的库,但即使如此,最常见的用途是间接的(例如使用一个bitset容器)。 另外,理想情况下,这些将是标准的库函数 – 在一些平台上,使用专门的CPU指令可以更好地处理这些函数。
1)除以2的幂
foo >>= x;
(除以2的幂)
foo <<= x;
(乘以2的幂)
2)交换
x ^= y; y = x ^ y; x ^= y;
虽然乘法/移位似乎很漂亮,但我偶尔需要的唯一一件事就是将布尔变换成位。 为此,您需要按位与/或,并可能位移/倒置。
我想要一个函数来将数字舍入到下一个最高次幂,所以我访问了几次被提出的Bit Twiddling网站,并提出了这个问题:
i--; i |= i >> 1; i |= i >> 2; i |= i >> 4; i |= i >> 8; i |= i >> 16; i++;
我在size_t
types上使用它。 它可能不会在签名types上发挥作用。 如果您担心可移植到不同大小types的平台,请在适当位置使用#if SIZE_MAX >= (number)
指令来洒上您的代码。
我使用按位运算符来高效地实现位串的距离计算。 在我的应用程序中,位串被用来表示位置在一个离散的空间(一个八叉树 ,如果你感兴趣,用莫顿sorting编码)。 距离计算需要知道网格上的点是否落在特定的半径内。