我一直试图想出一些方法,我可以同时进行两次比较,找到最大/最少的三个数字。在这种情况下,对它们的算术运算被认为是“免费的”。
也就是说,找到两个中较大者的经典方法,然后将其与第三个数字进行比较在这种情况下无效,因为一个比较取决于另一个的结果。
在不是这种情况下,是否可以使用两种比较?我想也许可以比较某些数字或他们的产品或其他东西的数字差异,但没有提出任何结果。
重新强调,仍然进行了两次比较,只是两种比较都不依赖于其他比较的结果。
到目前为止很棒的答案,谢谢你们
答案 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)
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