Given is an array of three numeric values and I\'d like to know the middle value of the three.
The question is, what is the fastest way of finding the midd
It's possible to answer the query without branches if the hardware can answer min and max queries without branches (most CPUs today can do this).
The operator ^ denotes bitwise xor.
Input: triple (a,b,c)
1. mx=max(max(a,b),c)
2. mn=min(min(a,b),c)
3. md=a^b^c^mx^mn
4. return md
This is correct because:
The appropriate min/max functions should be chosen for int/float. If only positive floats are present then it's possible to use integer min/max directly on the floating point representation (this could be desirable, since integer operations are generally faster).
In the unlikely scenario that the hardware doesn't support min/max, it's possible to do something like this:
max(a,b)=(a+b+|a-b|)/2
min(a,b)=(a+b-|a-b|)/2
However, this isn't correct when using float operations since the exact min/max is required and not something that's close to it. Luckily, float min/max has been supported in hardware for ages (on x86, from Pentium III and onwards).
You might as well write this in the most straightforward, way. As you said, there are only six possibilities. No reasonable approach is going to be any faster or slower, so just go for something easy to read.
I'd use min() and max() for conciseness, but three nested if/thens would be just as good, I think.
This one will work:
template<typename T> T median3_1_gt_2(const T& t1, const T& t2, const T& t3) {
if (t3>t1) {
return t1;
} else {
return std::max(t2, t3);
}
}
template<typename T> T median3(const T& t1, const T& t2, const T& t3) {
if (t1>t2) {
return median3_1_gt_2(t1, t2, t3);
} else {
return median3_1_gt_2(t2, t1, t3);
}
}
https://github.com/itroot/firing-ground/blob/864e26cdfced8394f8941c8c9d97043da8f998b4/source/median3/main.cpp
// Compute median of three values, no branches
int median3(int V[3])
{
unsigned int A,B,C;
A=(V[0] < V[1]);
B=(V[1] < V[2]);
C=(V[0] < V[2]);
return V[(B^C)<<1 | (A^B^1)];
}
There's an answer here using min/max and no branches (https://stackoverflow.com/a/14676309/2233603). Actually 4 min/max operations are enough to find the median, there's no need for xor's:
median = max(min(a,b), min(max(a,b),c));
Though, it won't give you the median value's index...
Breakdown of all cases:
a b c
1 2 3 max(min(1,2), min(max(1,2),3)) = max(1, min(2,3)) = max(1, 2) = 2
1 3 2 max(min(1,3), min(max(1,3),2)) = max(1, min(3,2)) = max(1, 2) = 2
2 1 3 max(min(2,1), min(max(2,1),3)) = max(1, min(2,3)) = max(1, 2) = 2
2 3 1 max(min(2,3), min(max(2,3),1)) = max(2, min(3,1)) = max(2, 1) = 2
3 1 2 max(min(3,1), min(max(3,1),2)) = max(1, min(3,2)) = max(1, 2) = 2
3 2 1 max(min(3,2), min(max(3,2),1)) = max(2, min(3,1)) = max(2, 1) = 2
Based on the excellent answer from Gyorgy, you can get the median's index without branches by replacing min/max with conditional moves:
int i = (array[A] >= array[B]) ? A : B;
int j = (array[A] <= array[B]) ? A : B;
int k = (array[i] <= array[C]) ? i : C;
int median_idx = (array[j] >= array[k]) ? j : k;
javac should generate a ConditionalNode for each of these ternary assignments, which translate to cmp/cmov
pairs in assembly. Also note the comparisons were chosen such that in case of equality, the first index in alphabetical order is returned.