在没有比较运算符的情况下找到2个数字之间的最小值

时间:2019-05-30 07:35:56

标签: c++ c bit-manipulation bitwise-operators bitwise-and

我已经看到了以下方法,该方法在没有关系运算符的情况下给出了最小值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/

谢谢

3 个答案:

答案 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进行无符号化才能确定地移位。