我已经看到了以下方法,该方法在没有关系运算符的情况下给出了最小值b / w 2的数字
foreach(KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
{
if (Input.GetKey(kcode))
Debug.Log("KeyCode down: " + kcode);
}
在这里,如果x = 6且y = 4 x-y = 2为正,并将此值向右移31次,则得到0。(因为+ ve数的符号位为0),等式变为
y + ((x - y) & ((x - y) >>(sizeof(int) * CHAR_BIT - 1)))
从上面的等式n中我们得到y为最小值,这是正确的。
但是对于x = 4和y = 6的情况,x-y = -2并将其向右移动31次将得到1,并且等式变为:
y + ((x-y)&0)
根据我的理解,-2和1的按位&变为0,并且eqn给出o / p为y(6)而不是x(4)。有人可以解释吗?
完整代码:https://www.geeksforgeeks.org/compute-the-minimum-or-maximum-max-of-two-integers-without-branching/
谢谢
答案 0 :(得分:3)
上述网站上的解释有误。当x < y
(x - y) >> 31 = 0b1...1 (32 ones) (*)
然后
y + ((x - y) & 0b1...1) = y + (x - y) = x
(*)请注意,负数的右移是实现定义的。通常,它执行arithmetic right shift,用二进制补码表示中的负数,用最高有效位1
填充所有二进制数字。
答案 1 :(得分:2)
在许多体系结构上,这种方法效率不高,而且比“常规”方法慢。我还应该提到,它不可读且容易出错。
示例:
int foo(int x, int y)
{
return (y + ((x - y) & ((x - y) >>(sizeof(int) * CHAR_BIT - 1))));
}
int foo1(int x, int y)
{
return x > y ? y : x;
}
及其生成的代码(ARM Cortex):
foo:
sub r0, r0, r1
and r0, r0, r0, asr #31
add r0, r0, r1
bx lr
foo1:
cmp r0, r1
movge r0, r1
bx lr
或x86
foo:
sub edi, esi
mov eax, edi
sar eax, 31
and eax, edi
add eax, esi
ret
foo1:
cmp edi, esi
mov eax, esi
cmovle eax, edi
ret
答案 2 :(得分:2)
在批准新标准之前,带符号整数的表示形式基于实现,并且对它们的>>也表示为整数(<<是UB)。假设平台的带符号值是2的补码,那么二进制中的-2是11111111111111111111111111111110110。将其右移31次实际上可能会导致所有位的值(等于-1)或值1的值,具体取决于实现。应当static_cast
进行无符号化才能确定地移位。