开发人员应该了解哪些有用的按位运算符代码技巧? [关闭]

Posted

技术标签:

【中文标题】开发人员应该了解哪些有用的按位运算符代码技巧? [关闭]【英文标题】:What USEFUL bitwise operator code tricks should a developer know about? [closed] 【发布时间】:2010-12-04 17:22:56 【问题描述】:

我必须说我从来没有使用按位运算符的理由,但我确信我已经执行了一些操作,使用它们可以更有效地完成。 “shifting”和“OR-ing”如何帮助您更有效地解决问题?

【问题讨论】:

您介意更改您接受的答案以选择 CS 的答案吗? @Xam - CS 的答案比 Martin 的答案晚了将近 4 年,在我需要它的时候它对我很有启发性。所以原则上我不会改变它,但是 CS 和 Mohasin 都从投票中受益,这使得他们的答案比 Martin 的更受欢迎。 【参考方案1】:

对字符串(字符)使用按位运算

将字母转换为小写

OR 按空格 => (x | ' ') 即使字母已经小写,结果也总是小写 例如。 ('a' | ' ') => 'a' ; ('A' | ' ') => 'a'

将字母转换为大写

AND 下划线 => (x & '_') 即使字母已经是大写,结果也总是大写 例如。 ('a' & '_') => 'A' ; ('A' & '_') => 'A'

反转字母的大小写:

XOR 按空格 => (x ^ ' ') 例如。 ('a' ^ ' ') => 'A' ; ('A' ^ ' ') => 'a'

字母在字母表中的位置

AND by chr(31)/binary('11111')/(hex('1F') => (x & "\x1F") 结果在 1..26 范围内,字母大小写不重要 例如。 ('a' & "\x1F") => 1 ; ('B' & "\x1F") => 2

获取字母在字母表中的位置(仅适用于大写字母):

AND by ? => (x & '?') XOR by @ => (x ^ '@') 例如。 ('C' & '?') => 3 ; ('Z' ^ '@') => 26

获取字母在字母表中的位置(仅适用于小写字母):

XOR by backtick/chr(96)/binary('1100000')/hex('60') => (x ^ '`') 例如。 ('d' ^ '`') => 4 ; ('x' ^ '`') => 25

注意:使用非英文字母会产生垃圾结果

【讨论】:

你怎么知道我会感兴趣.... :) @Ka:这也适用于 javascript 吗?我在firebug's console 中尝试过这些,但我总是得到0 @Razort4x 它通过fromCharCode 和charCodeAt 在JS 中工作。例如。 String.fromCharCode("a".charCodeAt(0) & 95);【参考方案2】:
整数 (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; // (3<<5) ==>3 * 2^5 ==> 96

除以 2 的 m 次方

n >> m; // (20>>2) ==>(20/( 2^2) ==> 5

查奇数

(n & 1) == 1;

交换两个值

a ^= b;
b ^= a;
a ^= b;

获取绝对值

(n ^ (n >> 31)) - (n >> 31);

获取两个值的最大值

b & ((a-b) >> 31) | a & (~(a-b) >> 31);

获取两个值的最小值

a & ((a-b) >> 31) | b & (~(a-b) >> 31);

检查两者的符号是否相同

(x ^ y) >= 0;

计算 2^n

2 << (n-1);

是否是2的阶乘

n > 0 ? (n & (n - 1)) == 0 : false;

对 m 取模 2^n

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; 

如果 (x==a) x=b;如果 (x==b) x=a;

x = a ^ b ^ x;

【讨论】:

Math.floor() === x >> 0 和 Math.ceil() === y | 1个 据我所知,位运算符仅适用于整数和字符,不适用于实数值类型。您将 Math.floor 或 Math.ceil 与实数值而非整数一起使用。 if (x==a) x=b; if (x==b) x=a; 的意义何在?它相当于if (x == b) x = a;对比度数的术语是否定值或二进制补码,使用-n 可以更轻松地完成 @phuclv 我认为这些操作在您使用低级语言进行操作时非常有用。无需用低级语言编写复杂的“if-else”和分支逻辑,以这种方式实现逻辑变得容易。 @BraveNinja 这里没有复杂的 if-else。如果架构有条件移动,则只需要一次比较然后跳转,或者根本不需要跳转。此外,它并不是一个有用的技巧,因为它实际上可能由于依赖关系而比正常分配要慢【参考方案3】:

见著名的Bit Twiddling Hacks 大多数乘法/除法是不必要的 - 编译器会自动执行此操作,您只会让人们感到困惑。

但是,如果您使用硬件或通信协议,有很多“检查/设置/切换位 N”类型的技巧非常有用。

【讨论】:

【参考方案4】:

我用过的频率只有三个:

    设置一点: a |= 1 &lt;&lt; bit;

    清楚一点: a &amp;= ~(1 &lt;&lt; bit);

    测试是否设置了一个位: a &amp; (1 &lt;&lt; bit);

【讨论】:

【参考方案5】:

Matters Computational: Ideas, Algorithms, Source Code, by Jorg Arndt (PDF)。这本书包含大量内容,我通过http://www.hackersdelight.org/的链接找到了它

平均无溢出

计算两个平均值 (x + y)/2 的例程 参数 x 和 y 是

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);

【讨论】:

感谢本书链接!【参考方案6】:

1) 除以/乘以 2 的幂

foo &gt;&gt;= x;(除以 2 的幂)

foo &lt;&lt;= x;(乘以 2 的幂)

2) 交换

x ^= y;
y = x ^ y;
x ^= y;

【讨论】:

看看基准测试证明它们是否真的比现代编译器上的正常方式更快会很有趣。 我相信这种转变会更快。交换更多的是不需要额外的内存而不是更快。 @Taylor:大多数现代编译器会在最快的方式下使用 shift,而无需您手动编写代码。【参考方案7】:

您可以压缩数据,例如整数的集合:

查看哪些整数值在集合中出现的频率更高 Use short bit-sequences to represent the values which appear more frequently(以及更长的位序列来表示出现频率较低的值) 连接位序列:例如,结果位流中的前 3 位可能代表一个整数,然后接下来的 9 位代表另一个整数,等等。

【讨论】:

【参考方案8】:

我使用位运算符来有效地实现bitstrings 的距离计算。在我的应用程序中,位串用于表示离散空间中的位置(octree,如果您有兴趣,用Morton ordering 编码)。需要进行距离计算才能知道网格上的点是否落在特定半径内。

【讨论】:

【参考方案9】:

计数设置位、查找最低/最高设置位、从顶部/底部查找第 n 个设置位等可能很有用,值得关注 bit-twiddling hacks 站点。

也就是说,这种事情并不重要。拥有一个库很有用,但即便如此,最常见的用途也是间接的(例如,使用 bitset 容器)。此外,理想情况下,这些将是标准库函数 - 在某些平台上使用专门的 CPU 指令可以更好地处理其中的许多函数。

【讨论】:

【参考方案10】:

虽然通过移位进行乘法/除法看起来很漂亮,但我偶尔需要做的就是将布尔值压缩为位。为此,您需要按位与/或,并且可能需要位移/反转。

【讨论】:

【参考方案11】:

我想要一个将数字四舍五入的函数,因此我访问了被多次提及的 Bit Twiddling 网站并想出了这个:

i--;
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
i++;

我在 size_t 类型上使用它。它可能在签名类型上效果不佳。如果您担心对不同大小类型平台的可移植性,请在适当的地方使用#if SIZE_MAX &gt;= (number) 指令。

【讨论】:

以上是关于开发人员应该了解哪些有用的按位运算符代码技巧? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

128 位整数之间的按位运算

Delphi中的按位补码。 (翻译C#〜运算符)

C语言中while语句里使用scanf的技巧

位掩码 - C中的按位运算

C语言里的按位异或运算符

Apache Pig 中的按位运算?