【C】求两个整型数字的平均值

方法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;
}

输出结果



猜你喜欢

转载自blog.csdn.net/sustzc/article/details/79615022