求两个正整数均值(防溢出)

两个整数平均数(防溢出,向下取整)

已知两个整数abab的值均没有出现溢出,而a + b有可能出现溢出,例如在归并排序中,通过mid = (low + high)/2求中位值,就可能整数溢出问题。现在需要在防止溢出的情况下求a和b的平均值,该平均值取其实际值的向下取整。

  • 思路一:求两个数的平均值最常见的思路就是将两个数相加,然后除以2,但是此处两个数相加可能出现溢出;

  • 思路二:可以考虑将ab先分别除以2,再求和。但程序中整数相除,通常向下取整(如Java),直接a/2 + b/2可能出现平均数偏差。例如求整数35平均值,在Java3/2 + 5/2得到的值将会是3。这是因为Java中整数相除进行了向下取整,实际上Java3/2 = 15/2 = 2。为了避免这种情况,可以分别对a,b进行求商运算和求余运算,然后对商运算的结果和求余运算结果相加,如下:

    avg = a / 2 + b / 2 + (a % 2 + b % 2) / 2;

位运算求解

在思路二解法的基础上,利用计算机位运算特性,对2的取商运算和取余运算进行简化。在位运算中,对整数右移一位相当于除以2并向下取整,即对2求商;而对整数2取余只有两种情况,余数要么0,要么1,因此可以利用位运算中与运算&,整数对1进行与运算&,偶数得到余就是0,奇数得到余就是1。因此最终得到的程序算式如下:

     avg = (a >> 1) + (b >> 1) + (((a & 1) + (b & 1)) >> 1);
  • 需要注意程序语言中运算符优先级,Java中运算符优先级:() –> + –> >> –> &

以下给出两种方法的java代码:

    // 取商均值 + 取余均值
    public int getAvgOfTwoIntNormal(int a, int b) {
        int avg = a / 2 + b / 2 + (a % 2 + b % 2) / 2;
        return avg;
    }

    // 通过位运算
    public int getAvgOfTwoIntByBitwise(int a, int b) {
        //注意操作符优先级
        int avg = (a >> 1) + (b >> 1) + (((a & 1) + (b & 1)) >> 1);
        return avg;
    }

参考

在防止溢出的情况下求两个整数的平均数(向下取整)

点赞