TL:DR; Your code is already correct and "clean".
I see a lot of people waffling around the answer but everyone is missing the forest through the trees. Let's do the full computer science and mathematical analysis to completely understand this question.
First, we note that we have 3 variables, each with 3 states: <, =, or >. The total number of permutations is 3^3 = 27 states, which I'll assign an unique number, denoted P#, for each state. This P# number is a factorial number system.
Enumerating all the permutations we have:
a ? b | a ? c | b ? c |P#| State
------+-------+-------+--+------------
a < b | a < c | b < c | 0| C
a = b | a < c | b < c | 1| C
a > b | a < c | b < c | 2| C
a < b | a = c | b < c | 3| impossible a<b b<a
a = b | a = c | b < c | 4| impossible a<a
a > b | a = c | b < c | 5| A=C > B
a < b | a > c | b < c | 6| impossible a<c a>c
a = b | a > c | b < c | 7| impossible a<c a>c
a > b | a > c | b < c | 8| A
a < b | a < c | b = c | 9| B=C > A
a = b | a < c | b = c |10| impossible a<a
a > b | a < c | b = c |11| impossible a<c a>c
a < b | a = c | b = c |12| impossible a<a
a = b | a = c | b = c |13| A=B=C
a > b | a = c | b = c |14| impossible a>a
a < b | a > c | b = c |15| impossible a<c a>c
a = b | a > c | b = c |16| impossible a>a
a > b | a > c | b = c |17| A
a < b | a < c | b > c |18| B
a = b | a < c | b > c |19| impossible b<c b>c
a > b | a < c | b > c |20| impossible a<c a>c
a < b | a = c | b > c |21| B
a = b | a = c | b > c |22| impossible a>a
a > b | a = c | b > c |23| impossible c>b b>c
a < b | a > c | b > c |24| B
a = b | a > c | b > c |25| A=B > C
a > b | a > c | b > c |26| A
By inspection we see we have:
- 3 states where A is the max,
- 3 states where B is the max,
- 3 states where C is the max, and
- 4 states where either A=B, or B=C.
Let's write a program (see the footnote) to enumerate all these permutations with values for A, B, and C. Stable sorting by P#:
a ?? b | a ?? c | b ?? c |P#| State
1 < 2 | 1 < 3 | 2 < 3 | 0| C
1 == 1 | 1 < 2 | 1 < 2 | 1| C
1 == 1 | 1 < 3 | 1 < 3 | 1| C
2 == 2 | 2 < 3 | 2 < 3 | 1| C
2 > 1 | 2 < 3 | 1 < 3 | 2| C
2 > 1 | 2 == 2 | 1 < 2 | 5| ??
3 > 1 | 3 == 3 | 1 < 3 | 5| ??
3 > 2 | 3 == 3 | 2 < 3 | 5| ??
3 > 1 | 3 > 2 | 1 < 2 | 8| A
1 < 2 | 1 < 2 | 2 == 2 | 9| ??
1 < 3 | 1 < 3 | 3 == 3 | 9| ??
2 < 3 | 2 < 3 | 3 == 3 | 9| ??
1 == 1 | 1 == 1 | 1 == 1 |13| ??
2 == 2 | 2 == 2 | 2 == 2 |13| ??
3 == 3 | 3 == 3 | 3 == 3 |13| ??
2 > 1 | 2 > 1 | 1 == 1 |17| A
3 > 1 | 3 > 1 | 1 == 1 |17| A
3 > 2 | 3 > 2 | 2 == 2 |17| A
1 < 3 | 1 < 2 | 3 > 2 |18| B
1 < 2 | 1 == 1 | 2 > 1 |21| B
1 < 3 | 1 == 1 | 3 > 1 |21| B
2 < 3 | 2 == 2 | 3 > 2 |21| B
2 < 3 | 2 > 1 | 3 > 1 |24| B
2 == 2 | 2 > 1 | 2 > 1 |25| ??
3 == 3 | 3 > 1 | 3 > 1 |25| ??
3 == 3 | 3 > 2 | 3 > 2 |25| ??
3 > 2 | 3 > 1 | 2 > 1 |26| A
In case you were wondering how I knew which P# states were impossible, now you know. :-)
The minimum number of comparisons to determine the order is:
Log2(27) = Log(27)/Log(2) = ~4.75 = 5 comparisons
i.e. coredump gave the correct 5 minimal number of comparisons. I would format his code as:
status_t index_of_max_3(a,b,c)
{
if (a > b) {
if (a == c) return DONT_KNOW; // max a or c
if (a > c) return MOSTLY_A ;
else return MOSTLY_C ;
} else {
if (a == b) return DONT_KNOW; // max a or b
if (b > c) return MOSTLY_B ;
else return MOSTLY_C ;
}
}
For your problem we don't care about testing for equality so we can omit 2 tests.
It doesn't matter how clean/bad the code is if it gets the wrong answer so this is a good sign that you are handling all the cases correctly!
Next, as for simplicity, people keep trying to "improve" the answer,
where they think improving means "optimizing" the number of comparisons,
but that isn't strictly what you are asking. You confused everyone where you asked
"I feel there might be a better" but didn't define what 'better' means. Less comparisons? Less code? Optimal comparisons?
Now since you are asking about code readability (given correctness) I would only make one change to your code for readability: Align the first test with the others.
if (a > b && a > c)
status = MOSTLY_A;
else if (b > a && b > c)
status = MOSTLY_B;
else if (c > a && c > b)
status = MOSTLY_C;
else
status = DONT_KNOW; // a=b or b=c, we don't care
Personally I would write it the following way but this may be too unorthodox for your coding standards:
if (a > b && a > c) status = MOSTLY_A ;
else if (b > a && b > c) status = MOSTLY_B ;
else if (c > a && c > b) status = MOSTLY_C ;
else /* a==b || b ==c*/status = DONT_KNOW; // a=b or b=c, we don't care
Footnote: Here is the C++ code to generate the permutations:
#include <stdio.h>
char txt[] = "< == > ";
enum cmp { LESS, EQUAL, GREATER };
int val[3] = { 1, 2, 3 };
enum state { DONT_KNOW, MOSTLY_A, MOSTLY_B, MOSTLY_C };
char descr[]= "??A B C ";
cmp Compare( int x, int y ) {
if( x < y ) return LESS;
if( x > y ) return GREATER;
/* x==y */ return EQUAL;
}
int main() {
int i, j, k;
int a, b, c;
printf( "a ?? b | a ?? c | b ?? c |P#| State\n" );
for( i = 0; i < 3; i++ ) {
a = val[ i ];
for( j = 0; j < 3; j++ ) {
b = val[ j ];
for( k = 0; k < 3; k++ ) {
c = val[ k ];
int cmpAB = Compare( a, b );
int cmpAC = Compare( a, c );
int cmpBC = Compare( b, c );
int n = (cmpBC * 9) + (cmpAC * 3) + cmpAB; // Reconstruct unique P#
printf( "%d %c%c %d | %d %c%c %d | %d %c%c %d |%2d| "
, a, txt[cmpAB*2+0], txt[cmpAB*2+1], b
, a, txt[cmpAC*2+0], txt[cmpAC*2+1], c
, b, txt[cmpBC*2+0], txt[cmpBC*2+1], c
, n
);
int status;
if (a > b && a > c) status = MOSTLY_A;
else if (b > a && b > c) status = MOSTLY_B;
else if (c > a && c > b) status = MOSTLY_C;
else /* a ==b || b== c*/status = DONT_KNOW; // a=b, or b=c
printf( "%c%c\n", descr[status*2+0], descr[status*2+1] );
}
}
}
return 0;
}
Edits: Based on feedback, moved TL:DR to top, removed unsorted table, clarified 27, cleaned up code, described impossible states.