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

Finding minimum value between 2 numbers without comparision operators

本文关键字:数字 最小值 之间 查找 情况下 比较 运算符      更新时间:2023-10-16

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

从上面的 eqn 中,我们得到 y 作为最小值,这是真的。

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

y + ((x-y)&1)

根据我的理解,-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/

谢谢

上述网站上给出的解释是错误的。当x < y

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

然后

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

(*( 请注意,负数的右移是实现定义的。通常,它执行算术右移,用最重要的数字填充所有二进制数字,该数字在二进制补码表示中1负数。

在许多架构上,它的效率不高,速度也比"正常"方式慢。我还应该提到它不可读且非常容易出错。

例:

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

在新标准被批准之前,有符号整数的表示是基于实现的,并且>>它们(<<是 UB(。假设平台将有符号值作为 2 的补码,那么二进制中的 -2 11111111111111111111111111111110。将其向右移动 31 次实际上可能会导致所有位集的值(等于 -1(或值为 1,具体取决于实现。它应该static_cast到未签名才能以明确的方式转移。