使用位操作来计算两个数的平均值?

时间:2017-05-22 09:26:23

标签: bit-manipulation

我找到了这段代码:

int mid = (l & r) + ((l ^ r) >> 1)

mid=(l+r)/2

相同

但我无法理解为什么?

有任何帮助吗?谢谢!

1 个答案:

答案 0 :(得分:3)

它不完全相同,重点不一样。它大多数相同,但没有溢出问题:如果你输入两个正数,结果永远不会是负数。 mid = (l + r) / 2不是这样,如果你有l = 0x7fffffff, r = 1,那么真正的中点是0x40000000,但是天真的中点计算表明它是0xc0000000,一个很大的负数。

添加可以分解为:

x + y = (x ^ y) + ((x & y) << 1)

这只是一个简单的“每位数的计算总和,然后单独应用进位”分解。然后将整个事物向右移动1,同时通过不向左移动开始并将另一个向右移动来恢复“从末端掉落”的位,

x + y = ((x ^ y) >> 1) + (x & y)

这是中点计算。请注意,它向向下舍入,而不是向零,这对于负面结果很重要。我不会将结果称为错误,它仍然位于端点之间,但它与正常签名除法的结果不匹配2(通常是向零舍入,尽管有关如何舍入的意见不同)。

您可以使用无符号右移来将其更改为适用于所有无符号整数:

// unsigned midpoint without wrapping/overflow
int mid = (l & r) + ((l ^ r) >>> 1);

当然是无符号中点,负输入被隐含地视为非常大的正数,这就是重点。

如果你正在使用有符号但非负数的数字(通常是中点计算的情况),你可以使用更简单的

int mid = (x + y) >>> 1