两个整数平均数(防溢出,向下取整)
已知两个整数a
、b
,a
和b
的值均没有出现溢出,而a + b
有可能出现溢出,例如在归并排序中,通过mid = (low + high)/2
求中位值,就可能整数溢出问题。现在需要在防止溢出的情况下求a和b的平均值,该平均值取其实际值的向下取整。
思路一:求两个数的平均值最常见的思路就是将两个数相加,然后除以
2
,但是此处两个数相加可能出现溢出;思路二:可以考虑将
a
和b
先分别除以2
,再求和。但程序中整数相除,通常向下取整(如Java
),直接a/2 + b/2
可能出现平均数偏差。例如求整数3
和5
平均值,在Java
中3/2 + 5/2
得到的值将会是3
。这是因为Java
中整数相除进行了向下取整,实际上Java
中3/2 = 1
,5/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;
}