在 Go 中使用位操作在两个数字之间查找最小值和最大值



以下函数的 Go 语法中的等效项是什么:

/*Function to find minimum of x and y*/
public  static int min(int x, int y) { 
return y ^ ((x ^ y) & -(x < y)); 
} 
/*Function to find maximum of x and y*/
public  static int max(int x, int y) { 
return x ^ ((x ^ y) & -(x < y)); 
} 

我发现很难写的部分是x小于y检查的否定。我有一个使用文章中第二个建议的版本:

min := y + ((x - y) & ((x - y) >> 31 ))
max := x - ((x - y) & ((x - y) >> 31 ))

我想要一种位操作方法来避免使用分支。

来自 http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax 的代码源

请注意,这里已经讨论了这个问题,但没有在 Go 的上下文中讨论过。似乎该方法对x-y具有未定义的行为。

由于表达式x < y的计算结果为 Go 中的bool,因此您需要使用if语句将结果转换为01。 否则,Go 中的运算符与 C++ 中的运算符相同。

func Min(x, y int) int {
var s int
if x < y {
s = -1
}
return y ^ ((x ^ y) & s)
}
func Max(x, y int) int {
var s int
if x < y {
s = -1
}
return x ^ ((x ^ y) & s)
}

能做到吗?可以说是的,但是以符合您标准的方式将布尔值转换为整数会导致奇怪的黑客攻击,例如:

func convertBoolToInt(b bool) int {
return *(*int)(unsafe.Pointer(&b)) & 1
}

这当然公然读取的字节数比写入b地址的字节多,& 1摆脱了任何"脏位",但这绝对是一个黑客。

然后,这可以用于比较以将它们转换为整数:

y ^ ((x ^ y) & -convertBoolToInt(x < y))

关于y + ((x - y) & ((x - y) >> 31 )),正如链接的文章所指出的,它对输入有一些限制。实际上,它适用于75%的可能输入。

在许多情况下,这种限制是可以接受的,因为它中断的输入远远超出"通常使用的值"。因为当它不可接受时,这里有一个替代方案。"比较掩码"(相当于-(x < y))可以计算为((x - y) ^ ((x ^ y) & ((x - y) ^ x))) >> 31(来源:黑客的喜悦第2章,基础)。将其代入第一种方法,我们得到:

func min(x int, y int) int { 
return y ^ ((x ^ y) & (((x - y) ^ ((x ^ y) & ((x - y) ^ x))) >> 31))
}

明显的缺点是它花费更多的操作。

相关内容

  • 没有找到相关文章

最新更新