Java 两个整数(或长整数)的平均值,无溢出,向0截断
我想要一种方法来计算Java中任意两个整数x,y的Java 两个整数(或长整数)的平均值,无溢出,向0截断,java,math,overflow,bit-manipulation,Java,Math,Overflow,Bit Manipulation,我想要一种方法来计算Java中任意两个整数x,y的(x+y)/2。如果x+y>Integer.MAX\u值或
(x+y)/2
。如果x+y>Integer.MAX\u值或IntMath
这种技术:
public static int mean(int x, int y) {
// Efficient method for computing the arithmetic mean.
// The alternative (x + y) / 2 fails for large values.
// The alternative (x + y) >>> 1 fails for negative values.
return (x & y) + ((x ^ y) >> 1);
}
。。。但是这一轮朝着负无穷大,这意味着例程不同意像{1,-2}(给出-2,而不是-1)这样的值的天真方式
是否有向0截断的相应例程
“只要使用
long
”并不是我想要的答案,因为我想要一种也适用于长输入的方法biginger
也不是我想要的答案。我不想要任何分支的解决方案。为什么不做一些类似于(x-y)/2+y
的事情,这会减少到x/2-y/2+y=x/2+y/2
?因此,如果x+y
给你一个上溢或下溢,你可以用(x-y)/2+y
的方式来做。如果最低位不同,你需要向结果中添加1
(因此结果不精确,需要四舍五入),并设置结果中的符号位(结果为负,因此您希望将向下舍入改为向上舍入)
因此,应采取以下措施(未经测试):
“我不想要任何分支的解决方案。”-即使最好的无分支解决方案比有分支的最佳解决方案慢也不行?这里有一个针对C++的解决方案:。它也应该适用于Java。你是对的-如果有一个有分支的解决方案在随机输入上比无分支的解决方案性能更好,我很乐意使用它。我想我显示了我的偏见-我怀疑这样的解决方案是否存在:)@Stephen C-您链接到的解决方案仅适用于无符号值(因此,实际上可能最好用guava版本代替)。当值为负值时,它仍然向负无穷大方向旋转。
x-y
可能会下溢,这与原始值一样有问题。另外,如果分支预测得不好,那么它们的速度会非常慢。我认为如果x+y
溢出/下溢,那么x-y
不可能下溢/上溢……当然,但这意味着您需要检查x+y是否溢出,引入一个分支,如果输入数据是随机分布的,那么这个分支的预测会非常差(因为很多组合都会溢出/溢出)。这就是我说“没有分支”的原因。我找不到更快的组合。
public static int mean(int x, int y) {
int xor = x ^ y;
int roundedDown = (x & y) + (xor >> 1);
return roundedDown + (1 & xor & (roundedDown >>> 31));
}