I am looking for the best solution to finding a median of 3. I want it to be in the least lines possible. Thank you in advance :) I've tried sth like this:
int median(int a, int b, int c)
{
if ((a >= b && a <= c) || (a <= b && a >= c)) return a;
if ((b >= a && b <= c) || (b <= a && b >= c)) return b;
return c;
}
I believe this solution is okay, but maybe there is something better?
CodePudding user response:
int median(int a, int b, int c)
{
return ((b > a) == (a > c)) ? a : ((a > b) == (b > c)) ? b : c;
}
https://godbolt.org/z/4G3dzPcs3
Above code has small bug in it (prove that tests are important), here is fixed version:
int median(int a, int b, int c)
{
return (b > a) == (a > c) ? a : (b > a) != (b > c) ? b : c;
}
https://godbolt.org/z/8bq38hvaj (contains testcase reviling bug in earlier code).
CodePudding user response:
How about
int median(int a, int b, int c) {
std::vector<int> result = { a,b,c };
std::sort(result.begin(), result.end());
return result[1];
}
CodePudding user response:
This should work for all platform int values, and supports duplicates (e.g. cases of two, or all three arguments being equivalent).
int median(int a, int b, int c)
{
return ((a > b) ^ (a > c)) ? a : ((b < a) ^ (b < c)) ? b : c;
}
Example O2 optimized asm:
clang 12.0.1
median:
mov eax, edx
cmp edi, esi
setg r8b
cmp edi, edx
setg dl
xor dl, r8b
cmp esi, eax
setl cl
xor cl, r8b
cmovne eax, esi
test dl, dl
cmovne eax, edi
ret
gcc 11.2
median:
cmp edi, esi
mov eax, edi
setg cl
cmp edi, edx
setg dil
cmp cl, dil
je .L5
ret
.L5:
cmp esi, edx
setl al
cmp cl, al
mov eax, edx
cmovne eax, esi
ret
CodePudding user response:
Short can be cryptic to read:
return a < b ? c < a ? a : b < c ? b : c : c < b ? b : a < c ? a : c;
I can add redundant parentheses to clarify but unsure if it clarifies anything:
return a < b ? (c < a ? a : b < c ? b : c) : c < b ? b : a < c ? a : c;
CodePudding user response:
Enumerating all possibilities is certainly one way. But we can also factor out a comparison - after all, the result of a < b already tells you the relative ordering of those two.
int median3(int a, int b, int c) {
// Sort a and b
int lo, hi;
if (a <= b) {
lo = a;
hi = b;
} else {
lo = b;
hi = a;
}
// Check where c lies relative to hi & lo
if (c > hi) {
return hi;
} else if (c < lo) {
return lo;
} else {
return c;
}
}
Whether to consider this "better" (or more readable) is probably a matter of taste.
CodePudding user response:
int getMedian(int a, int b , int c) {
int p = a-b,q=b-c,r=a-c;
if(p*q > 0) return b;
return p*r > 0?c:a;
}
This will do
CodePudding user response:
first google search: https://www.geeksforgeeks.org/middle-of-three-using-minimum-comparisons/
after some more search found this: Fastest way of finding the middle value of a triple?
median = max(min(a,b), min(max(a,b),c));
CodePudding user response:
The best implementation is clearly a question of taste.
When possible, I prefer to manipulate boolean expressions, and to limit the number of comparisons.
#include <iostream>
int median (int a, int b, int c) {
auto tab = (a < b), tac = (a < c), tbc = (b < c);
if (tab xor tac) return a;
if (!tab xor tbc) return b;
return c;
}
int main() {
std::cout << median (1, 2, 3) << std::endl;
std::cout << median (1, 3, 2) << std::endl;
std::cout << median (2, 1, 3) << std::endl;
std::cout << median (2, 3, 1) << std::endl;
std::cout << median (3, 2, 1) << std::endl;
std::cout << median (3, 1, 2) << std::endl;
std::cout << median (1, 2, 2) << std::endl;
std::cout << median (2, 2, 3) << std::endl;
std::cout << median (2, 2, 1) << std::endl;
return 0;
}
