是否可以通过同时使用两个比较来计算三个数字的最小值?

时间:2013-11-06 20:36:58

标签: algorithm comparison

我一直试图想出一些方法,我可以同时进行两次比较,找到最大/最少的三个数字。在这种情况下,对它们的算术运算被认为是“免费的”。

也就是说,找到两个中较大者的经典方法,然后将其与第三个数字进行比较在这种情况下无效,因为一个比较取决于另一个的结果。

在不是这种情况下,是否可以使用两种比较?我想也许可以比较某些数字或他们的产品或其他东西的数字差异,但没有提出任何结果。

重新强调,仍然进行了两次比较,只是两种比较都不依赖于其他比较的结果。

到目前为止很棒的答案,谢谢你们

7 个答案:

答案 0 :(得分:5)

忽略等值(“关系”)的可能性,有3个! := 6个可能的三个项目的排序。如果比较恰好产生一位,则两次比较只能编码2 * 2:= 4种可能的配置。并且4< 6. IOW:您无法使用两个固定比较来决定三个项目的顺序。


使用真值表:

a b c|min|a<b a<c b<c| condition needed using only a<b and a<c
-+-+-+---+---+---+---+------------------
1 2 3| a | 1   1   1 | (ab==1 && ac==1)
1 3 2| a | 1   1   0 |  ...
2 1 3| b | 0   1   1 | (ab==0 && ac==1)
3 1 2| b | 0   0   1 | (ab==0 && ac==0) <<--- (*)
2 3 1| c | 1   0   0 | (ab==1 && ac==0)
3 2 1| c | 0   0   0 | (ab==0 && ac==0) <<--- (*)

正如您所看到的,当仅使用(*)a<b比较时,您无法区分由a<c标记的两种情况。 (选择另一组两个比较当然会失败,(通过对称))。

但遗憾的是:我们无法仅使用两个来编码三个可能的结果。 (是的,我们可以,但我们需要进行第三次比较,或根据第一次比较选择第二次比较)

答案 1 :(得分:3)

我认为这是可能的(根据问题的原始形式,以下是最小值):

B_lt_A = B < A
C_lt_min_A_B = C < (A + B - abs(A - B)) / 2

然后你把这些结合起来(我必须按顺序写它,但这是一个3路开关):

if (C_lt_min_A_B) then C is the min
else if (B_lt_A)  then B is the min
else                   A is the min

您可能会认为abs()意味着比较,但这取决于硬件。整数有a trick to do it without comparison。对于IEEE 754浮点,只需将符号位强制为零。

关于(A + B - abs(A - B)) / 2:这是(A + B) / 2 - abs(A - B) / 2,即A和B的最小值是A和B之间距离中点的距离的一半。这可以再次应用于产生min(A,B,C),但是你失去了最小值的身份,即你只知道最小值的 ,但不是它来自哪里。

有一天,我们可能会发现,在某些情况下,并行化2次比较可以提供更好的周转时间,甚至吞吐量。谁知道,也许是为了某些矢量化,或者是某些MapReduce,或者是我们还不知道的事情。

答案 2 :(得分:1)

如果你只是在谈论整数,我认为你可以使用一些数学和一点小提琴进行零比较。给出三个int值a,b和c:

int d = ((a + b) - Abs(a - b)) / 2; // find d = min(a,b)
int e = ((d + c) - Abs(d - c)) / 2; // find min(d,c)

将Abs(x)实现为

int Abs(int x) {
    int mask = x >> 31;
    return (x + mask) ^ mask;
}

没有经过广泛测试,所以我可能错过了一些东西。 Abs bit twiddle的功劳归于这些来源

How to compute the integer absolute value

http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs

答案 3 :(得分:0)

来自Bit Twiddling Hacks

r = y ^ ((x ^ y) & -(x < y)); // min(x, y)

min = r ^ ((z ^ r) & -(z < r)); // min(z, r)

两次比较!

答案 4 :(得分:0)

如何找到最低要求:

If (b < a)
   Swap(a, b)

If (c < a)
   Swap(a, c)

Return a;

答案 5 :(得分:0)

你可以在理论上进行零比较,假设2的补数表示(并且右移一个带符号的数字保留其符号)。

    min(a, b) = (a+b-abs(a-b))/2
    abs(a) = (2*(a >> bit_depth)+1) * a

然后

    min(a,b,c) = min(min(a,b),c)

这是有效的,因为假设a >> bit_depth为正数提供0,为负数提供-1,则2*(a>>bit_depth)+1为正数提供1-1对于负数。这会得到signum函数,我们得到abs(a) = signum(a) * a

然后它只是min(a,b)公式的问题。这可以通过两种可能性来证明:

    case min(a,b) = a:
    min(a,b) = (a+b - -(a-b))/2
    min(a,b) = (a+b+a-b)/2
    min(a,b) = a

    case min(a,b) = b:
    min(a,b) = (a+b-(a-b))/2
    min(a,b) = (a+b-a+b)/2
    min(a,b) = b

因此min(a,b)的公式有效。

上述假设仅适用于abs()函数,如果您可以获得数据类型的0比较abs()函数,那么您就可以了。

例如,IEEE754浮点数据的符号位为最高位,因此绝对值仅表示清除该位。这意味着您也可以使用浮点数。

然后你可以在0比较中将其扩展到N个数的min

在实践中,很难想象这种方法会击败任何不是故意慢的东西。这完全是关于使用少于3次的独立比较,而不是在实践中比直接实现更快。

答案 6 :(得分:0)

if cos(1.5*atan2(sqrt(3)*(B-C), 2*A-B-C))>0 then 
  A is the max
else
  if cos(1.5*atan2(sqrt(3)*(C-A), 2*B-C-A))>0  then 
    B is the max
  else                   
    C is the max