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

Finding minimum value between 2 numbers without comparision operators

我看到下面的方法给出了最小值 b/w 2 个没有关系运算符的数字

y + ((x - y) & ((x - y) >>(sizeof(int) * CHAR_BIT - 1)))

在这里如果 x=6 和 y=4 x-y=2 是正数并且将这个值向右移动 31 次得到 0。(因为 +ve 数的符号位是 0)并且 eqn 变成

y + ((x-y)&0)

从上面的等式我们得到 y 作为最小值,这是正确的。

但是对于 x=4 和 y=6 的情况,x-y=-2 并将其向右移动 31 次得到 1 并且等式变为:

y + ((x-y)&1)

根据我的理解,-2 和 1 的按位 & 变为 0,方程式给出 o/p 作为 y(6) 而不是 x(4)。有人可以解释一下吗?

完整代码:https://www.geeksforgeeks.org/compute-the-minimum-or-maximum-max-of-two-integers-without-branching/

谢谢

该网站的解释有误。当x < y

(x - y) >> 31 = 0b1...1 (32 ones) (*)

然后

y + ((x - y) & 0b1...1) = y + (x - y) = x

(*) 注意负数的右移是implementation-defined。通常,它执行 arithmetic right shift,用二进制补码表示中的负数的最高有效位填充所有二进制数字 1

与 "normal" 方式相比,它在许多体系结构上效率不高且速度较慢。我还应该提到它不可读并且很容易出错。

示例:

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

在新标准获得批准之前,有符号整数的表示形式是 implementation-based,并且 >> 在它们上面也是如此(<< 是一个 UB)。假设平台得到有符号值作为 2 的补码,那么二进制中的 -2 是 11111111111111111111111111111110。将其右移 31 次实际上可能导致所有位设置的值(等于 -1)或值 1,具体取决于实现.应该是 static_cast 到 unsigned 以明确的方式移动。