有用的位运算Bit Twiddling Hacks

在研读Redis代码的时候偶然发现了这个网页:http://graphics.stanford.edu/~seander/bithacks.html,觉得很有趣于是就着位算法这个主题以Bit Twiddling Hacks的内容为主进行了一番梳理。后面会陆续补充更多的算法和应用场景与案例。

文章修改记录

日期 内容
2020-02-23 版本v1.0,基础内容整理,少量实验测试和证明

基础内容

运算符

特性

与 &,或 |

相同运算符满足交换律、结合律,不同运算符满足分配律

非 ~,负 -

~即按位取反;

按位取反再加1即得负数(补码表示),~v + 1 = -v;

异或 ^

相同bit得0,不同bit得1;

任意数和0异或不变,任意数和1异或则取反,任意数和自己异或得0;

异或可展开:a^b = (~a & b) | (a & ~b);


计算整数的符号

正整数返回+1,零返回0,负整数返回-1

四种算法,v=1234,循环一亿次记下总时间,单位毫秒:

 

算法

第一次

第二次

第三次

平均

1

v > 0 ? 1 : (v < 0 ? -1 : 0)

133

134

133

133.3

2

(v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1))

101

102

102

101.7

3

(v > 0) - (v < 0)

101

100

100

100.3

4

(v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1))

99

100

99

99.3

观察发现v取负数或0的时候,算法1的执行时间和算法2、3、4差不多。

测试环境是Intel i9-9900K,Windows10 Pro版,MinGW-W64,gcc 8.1.0-posix-sjlj-rt_v6-rev0,可见其分支指令的性能还是不错的。


检测两个整数有不同的符号

int x, y; // 输入值
bool f = ((x ^ y) < 0); // 当且仅当x和y的符号不同的时候,返回true,相比用乘法判断,对于较大的x和y不会溢出

计算两个整数的最小和最大值

同样是一亿次计算统计总时间:

 

算法

第一次

第二次

第三次

平均

1

x < y ? x : y // min(x, y)

x > y ? x : y // max(x, y)

148

148

148

148

2

y ^ ((x ^ y) & -(x < y)) // min(x, y)

x ^ ((x ^ y) & -(x < y)) // max(x, y)

134

135

136

135

测试环境是Intel i9-9900K,Windows10 Pro版,MinGW-W64,gcc 8.1.0-posix-sjlj-rt_v6-rev0


判断一个整数是否是2的幂

unsigned int v; // 待判断的值 
bool f = (v & (v - 1)) == 0; // 这里不包括0
bool f = v && !(v & (v - 1)); // 这里包括0

按条件设置或清除bit位(不带分支判断)

bool f; // 条件标记
unsigned int m; // bit掩码 
unsigned int w; // 被修改的word,逻辑: if (f) w |= m; else w &= ~m; 
w ^= (-f ^ w) & m; 
// 或者对于超标量CPU:
w = (w & ~m) | (-f & m);

证明:

1. w ^= (-f ^ w) & m;

当f=1(true)时,表达式可写为w ^ ((-1 ^ w) & m),因为-1为全1,w无符号,所以-1 ^ w = ~w,表达式化简为w ^ (~w & m),根据异或的性质a ^ b = (~a & b) | (a & ~b),展开表达式为(~w & ~w & m) | (w & (~(~w & m))) = (~w & m) | (w & (w | ~m)) = (~w & m) | (w | (w & ~m)) = (~w & m) | w = (~w | w) & (m | w) = m | w

当f=0(false)时,表达式可写成w ^ ((0 ^ w) & m) = w ^ (w & m) = (~w & w & m) | (w & ~(w & m)) = 0 | (w & (~w | ~m)) = (w & ~w) | (w & ~m) = w & ~m

2. w = (w & ~m) | (-f & m);

当f=1(true)时,表达式可写为(w & ~m) | (-1 & m) = (w & ~m) | m = (m | w) & (m | ~m) = m | w

当f=0(false)时,表达式可写成(w & ~m) | (0 & m) = w & ~m

证毕


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值