位运算实现两整数最值的代码中,位运算符的作用及原理是什么?
如何理解无分支求两整数最大/最小值的位运算实现?
嘿,这个问题问得挺有意思的!我来一步步拆解这两段看起来有点“黑魔法”的位运算代码,搞清楚每部分的作用和底层逻辑。
首先得明确两个关键前提:
- 在C这类语言里,布尔表达式
x < y的结果:如果成立返回1,不成立返回0。 - 整数的负数采用补码表示:
-1的二进制是全1(比如32位int就是0xFFFFFFFF),-0等价于0(全0)。
先看求最小值的min函数
int min(int x, int y) { return y ^ ((x ^ y) & -(x < y)); }
我们把代码拆成几个部分逐个分析:
-(x < y)的两种结果- 当
x < y为真时:-(1)就是-1,二进制全1; - 当
x < y为假时:-(0)就是0,二进制全0。
- 当
x ^ y的作用
异或运算的规则是:二进制位上相同为0,不同为1。所以这个结果里的每一位1,都代表x和y在该位上数值不同;0则代表两位数值相同。简单说,它存储了x和y的所有差异位。(x ^ y) & -(x < y)的筛选作用- 如果
x < y,和全1的数做与运算,结果就是x ^ y本身(任何数和全1与都等于自己); - 如果
x >= y,和全0做与运算,结果就是0。
这一步相当于根据x和y的大小关系,决定要不要保留两者的差异位。
- 如果
- 最后一步
y ^ 上面的结果- 当
x < y时:y ^ (x ^ y),根据异或的性质a ^ (a ^ b) = b,这里结果就是x——正好是较小的数; - 当
x >= y时:y ^ 0,结果就是y——也是较小的数。
- 当
再看求最大值的max函数
int max(int x, int y) { return x ^ ((x ^ y) & -(x < y)); }
逻辑和min函数几乎一致,只是最后一步从y ^ ...换成了x ^ ...:
- 同样,
-(x < y)还是两种结果:x < y时全1,否则全0; (x ^ y) & -(x < y)的结果也和min里一样:x < y时是x^y,否则是0;- 最后一步
x ^ 上面的结果- 当
x < y时:x ^ (x ^ y) = y——正好是较大的数; - 当
x >= y时:x ^ 0 = x——也是较大的数。
- 当
核心思路总结
这种写法的本质是用位运算模拟了条件选择,但没有使用分支语句(if/else)。它利用补码中-1全1、0全0的特性,通过与运算来“开关”差异位的保留,再通过异或运算把差异位对应的数值替换成另一个数,从而得到min或max。
这种无分支的实现,在一些对性能要求极高的场景(比如嵌入式、高频交易)很有用——因为它避免了分支预测失败带来的性能损耗。
内容的提问来源于stack exchange,提问作者Mr Josh




