方法1:两个数字相加除以2
源代码:
/* * 函数名称:AverageOne * * 函数功能:求两个整型数字的平均值(方法1) * * 入口参数:num1, num2 * * 出口参数:空 * * 返回类型:void */ void AverageOne(int num1, int num2) { int avg = 0; avg = (num1 + num2) / 2; printf("avg = %d\n", avg); return; }
不足:先求num1加num2的话整数会溢出。
方法2:想象下如何使得两根不一样长的树变得一样长,首先两棵树的高度作差,然后在对剩下的部分取半即可。
源代码:
/* * 函数名称:AverageTwo * * 函数功能:求两个整型数字的平均值(方法2) * * 入口参数:num3, num4 * * 出口参数:空 * * 返回类型:void */ void AverageTwo(int num3, int num4) { int avg = 0; avg = num3 + (num4 - num3) / 2; printf("avg = %d\n", avg); return; }
不足:该算法要执行三种运算,分别是:除法、加法以及减法,而执行除法操作是比较麻烦的(需要移位、逻辑判断以及累减),于是乎考虑使用移位运算来代替。
方法3:移位运算,逻辑右移一位相当于除以2,左边补0,左移一位相当于乘以2,右边补0。这里分别对两个数字逻辑右移一位再求和。
源代码:
/* * 函数名称:AverageThree * * 函数功能:求两个整型数字的平均值(方法3) * * 入口参数:num5, num6 * * 出口参数:空 * * 返回类型:void */ void AverageThree(int num5, int num6) { int avg = 0; avg = (num5 >> 1) + (num6 >> 1); printf("avg = %d\n", avg); return; }
方法4:首先,每个二进制数字可以分解为每个位上的数字乘其权积(也就是2)的和,那么当各位置上的数字同时为1时,按位与运算可以得到1,由于在加法运算中逢2(1+1=2)进1,所以按位与得到的值的二倍就是该位置上数字之和(ps:不只是1+1=2,还得乘该位置的权积)。其次,当两个位置上的数字不同时(即就是0或者1),那么按位异或得到的值就是1,由于该位置上两个数字相加的和就是1,所以按位异或得到的值就是该位置上的数字之和(ps:注意是系数乘权积之和)。二进制位的加法运算,无外乎这四种情况(1+1、1+0、0+1、0+0),1+1的情况可以通过按位与完成,1+0或者0+1的情况可以通过按位异或完成,至于0+0的情况,由于本身加起来和为0,然后再乘上权积,得到的也是0。综上所述,求两个整型数字平均值的运算就可以转换为 各位置上数字相同时的平均值(按位与) 加上 各位置上数字不同时的平均值(按位异或后右移一位),即就是
avg = (num7 & num8) + ((num7 ^ num8) >> 1)
下面通过剖析数字5加上数字9来说明,选择5和9这两个数字的原因是恰好满足四种情况:同为0,同为1,一个为0,一个为1。
int num1 = 5;// 5 0101 int num2 = 9;// 9 1001 // 相同位 01 //+相同位 01 // 10 2 // 相同位 01 //&相同位 01 // 01 1 = 2 / 2 // 不同位 01 //+不同位 10 // 11 12 // 不同位 01 //^不同位 10 // 11 12 //相同位的和 + 不同位的和 = 2 + 12 = 14 //即就是两个数字的和 5 + 9 = 14 //1.相同位数字按位与运算可以得到相同位数字加起来和的一半, //这是因为只有某一位同为1时,按位与运算才会得到1, //而同为0时,按位与运算得到0, //一个为0,另一个为1时,按位与得到的也是0, //这样通过相同位的按位与运算就可以得到相同位数字的和的一半。 //2.不同位数字按位异或可以得到不同位数字加起来的和, //这是因为某一位上两数字不相同时,按位异或可以得到1, //两数字同为0或者同为1时,按位异或可以得到0, //那么通过不同位的按位异或运算就可以得到不同位数字的和。 //3.求两个数字的平均值就可以转换为 //相同位的和的一半 加上 不同位的和的一半, //而相同位的和的一半就是相同位的按位与的结果, //不同位的和的一半就是不同位的按位异或的结果的一半, //也可以通过右移1位来实现。
源代码:
/* * 函数名称:AverageFour * * 函数功能:求两个整型数字的平均值(方法4) * * 入口参数:num7, num8 * * 出口参数:空 * * 返回类型:void */ void AverageFour(int num7, int num8) { int avg = 0; avg = (num7 & num8) + ((num7 ^ num8) >> 1); printf("avg = %d\n", avg); return; }
主函数:
int main(void) { AverageOne(10, 20); AverageTwo(65534, 65535); AverageThree(65534, 65535); AverageFour(65534, 65535); system("pause"); return 0; }
输出结果: