0

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?

Michał Turek
  • 701
  • 3
  • 21

8 Answers8

3
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).

Marek R
  • 32,568
  • 6
  • 55
  • 140
2

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];
}
  • `result` can be a `std::array`. And you only need to do `nth_element` (or `partial_sort`). And conceptually this is the better approach, but not what the asker wanted (least possible lines) – JHBonarius Feb 03 '22 at 10:14
  • heap is involved, so it is slow like hell – Marek R Feb 03 '22 at 10:58
2

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;
Öö Tiib
  • 10,809
  • 25
  • 44
2

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
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
0

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.

Benjamin Maurer
  • 3,602
  • 5
  • 28
  • 49
0
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

Giriteja Bille
  • 168
  • 1
  • 13
0

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));
Anton
  • 563
  • 4
  • 13
0

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;
}
Damien
  • 4,809
  • 4
  • 15
  • 20