用位操作实现求两个数a和b的平均值,只需将两个数的相同位提取出来,再将不同的位加在一起除2(即右移一位),用表达式说明即为:((a & b) + (a ^ b) >> 1),用这样的方式计算两个数的平均值可以防止数据溢出。但是请记住用这个表达式算出的结果永远是不超过真实平均值的最大整数,即若真实结果是-5.5,则此表达式给出的结果是-6,若真实平均值是-5,则表达式的结果是-5。
现在解释一下这个表达式的原理,求两个数的平均值我们把这两个操作数分成二进制位相同的部分和二进制位不同的部分,例如a=5(0101),b=6(0110),他们相同的部分为a0=0100,b0=0100,他们不同的部分为a1=0001,b1=0010,则:
(a + b) / 2 = (5 + 6) / 2
<=> ((0100 + 0001) + (0100 + 0010)) >> 1 (1)
<=> ((0100 + 0100) + (0001 + 0010)) >> 1 (2)
<=> (0100 + 0100) >> 1 + (0001 + 0010) >> 1 (3)
<=> 1000 >> 1 + 0011 >> 1 (4)
<=> 0100 + 0011 >> 1 (5)
<=> 0101
= 5
由以上(5)式即知(a + b) / 2 就是 ((a & b) + (a ^ b) >> 1),但是如果结果是负的浮点数,则这两个数表达式的结果并不一样,(a + b) / 2 的结果是对浮点结果取整,取整的方式是直接去掉小数,而((a & b) + (a ^ b) >> 1) 的结果是不超过结果的最大整数。
1 #include <stdio.h> 2 3 int main(void) 4 { 5 int a; 6 int b; 7 8 scanf ("%d%d", &a, &b); 9 while ((0 != a) || (0 != b)) 10 { 11 printf ("\n用 (a + b) / 2 计算的 %d 和 %d 的平均值为:\n", a, b); 12 printf ("%d\n", (a + b) / 2); 13 14 printf ("\n用 ((a & b) + ((a ^ b) >> 1)) 计算的 %d 和 %d 的平均值为:\n", a, b); 15 printf ("%d\n\n", ((a & b) + ((a ^ b) >> 1))); 16 17 scanf ("%d%d", &a, &b); 18 } 19 20 return(0); 21 }