Encuentre un máximo de tres números en C sin usar el enunciado condicional y el operador ternario

Tengo que encontrar un máximo de tres números proporcionados por el usuario, pero con algunas restricciones. No está permitido usar ninguna statement condicional. Intenté usar el operador ternario como a continuación.

max=(a>b?a:b)>c?(a>b?a:b):c 

Pero nuevamente está restringido al uso del operador ternario. Ahora no tengo ni idea de cómo hacer esto?

Aprovechando el cortocircuito en expresiones booleanas:

 int max(int a, int b, int c) { int m = a; (m < b) && (m = b); //these are not conditional statements. (m < c) && (m = c); //these are just boolean expressions. return m; } 

Explicación:

En la operación booleana AND como x && y , y se evalúa si y solo si x es verdadero. Si x es falso, entonces y no se evalúa, porque toda la expresión sería falsa, lo que se puede deducir sin siquiera evaluar y . Esto se denomina cortocircuito cuando el valor de una expresión booleana se puede deducir sin evaluar todos los operandos en él.

Aplica este principio al código anterior. Inicialmente m es a . Ahora bien, si (m < b) es verdadero, entonces eso significa que b es mayor que m (que en realidad es a ), por lo que la segunda subexpresión (m = b) se evalúa y m se establece en b . Sin embargo, si (m < b) es falso, la segunda subexpresión no se evaluará y m seguirá siendo a (que es mayor que b ). De manera similar, se evalúa la segunda expresión (en la siguiente línea).

En resumen, puede leer la expresión (m < x) && (m = x) siguiente manera: configure m a x si y solo si m es menor que x ie (m < x) es verdadero. Espero que esto te ayude a entender el código.

Código de prueba:

 int main() { printf("%d\n", max(1,2,3)); printf("%d\n", max(2,3,1)); printf("%d\n", max(3,1,2)); return 0; } 

Salida:

 3 3 3 

Demostración en línea: http://www.ideone.com/8045P

Tenga en cuenta que la implementación de max da advertencias porque las expresiones evaluadas no se utilizan:

prog.c: 6: advertencia: el valor calculado no se utiliza
prog.c: 7: advertencia: el valor calculado no se utiliza

Para evitar estas advertencias (inofensivas), puede implementar max como:

 int max(int a, int b, int c) { int m = a; (void)((m < b) && (m = b)); //these are not conditional statements. (void)((m < c) && (m = c)); //these are just boolean expressions. return m; } 

El truco es que ahora estamos lanzando las expresiones booleanas a void , lo que provoca la supresión de las advertencias :

Suponiendo que se trata de enteros, ¿qué tal?

 #define max(x,y) (x ^ ((x ^ y) & -(x < y))) int max3(int x, int y, int z) { return max(max(x,y),z); } 

Solo para agregar otra alternativa para evitar la ejecución condicional (que no es la que usaría, pero parecía que faltaba en el conjunto de soluciones):

 int max( int a, int b, int c ) { int l1[] = { a, b }; int l2[] = { l1[ a 

El enfoque usa (como la mayoría de los otros), el hecho de que el resultado de una expresión booleana cuando se convierte a int produce 0 o 1. La versión simplificada para dos valores sería:

 int max( int a, int b ) { int lookup[] { a, b }; return lookup[ a < b ]; } 

Si la expresión a es correcta, devolvemos b , cuidadosamente almacenada en el primer índice de la matriz de búsqueda. Si la expresión arroja un resultado falso, entonces devolvemos a que está almacenado como el elemento 0 de la matriz de búsqueda. Usando esto como un bloque de construcción, puedes decir:

 int max( int a, int b, int c ) { int lookup[ max(a,b), c ]; return lookup[ max(a,b) < c ]; } 

Que puede transformarse trivialmente en el código anterior al evitar la segunda llamada al max interno utilizando el resultado ya almacenado en la lookup[0] y alinear la llamada original a max(int,int) .


(Esta parte es solo otra prueba de que debes medir antes de sacar conclusiones precipitadas, ver la edición al final)

En cuanto a lo que realmente usaría ... bueno, probablemente el de @Foo Baa aquí modificado para usar una función en línea en lugar de una macro. La siguiente opción sería esta o la de @MSN aquí .

El denominador común de estas tres soluciones no presentes en la respuesta aceptada es que no solo evitan la construcción sintáctica de if o el operador ternario, sino que evitan la ramificación por completo, y eso puede tener un impacto en el rendimiento. El pronosticador de twig en la CPU no puede fallar cuando no hay twigs.


Al considerar el rendimiento, primero mida y luego piense

De hecho, he implementado algunas de las diferentes opciones para un máximo de 2 vías y analicé el código generado por el comstackdor. Las siguientes tres soluciones generan el mismo código de ensamblaje:

 int max( int a, int b ) { if ( a < b ) return b; else return a; } int max( int a, int b ) { return (a < b? b : a ); } int max( int a, int b ) { (void)((a < b) && (a = b)); return a; } 

Lo cual no es sorprendente, ya que los tres representan exactamente la misma operación. La información interesante es que el código generado no contiene ninguna twig. La implementación es simple con la instrucción cmovge (prueba llevada a cabo con g ++ en una plataforma Intel x64):

 movl %edi, %eax # move a into the return value cmpl %edi, %esi # compare a and b cmovge %esi, %eax # if (b>a), move b into the return value ret 

El truco está en la instrucción de movimiento condicional, que evita cualquier twig potencial.

Ninguna de las otras soluciones tiene ninguna twig, pero todas se traducen a más instrucciones de la CPU que nada de esto, lo que al final del día nos asegura que siempre debemos escribir código simple y dejar que el comstackdor lo optimice para nosotros.

ACTUALIZACIÓN: Al ver esto 4 años después, veo que falla mal si dos o más de los valores pasan a ser iguales. Reemplazar > por >= cambia el comportamiento, pero no soluciona el problema. Es posible que todavía sea recuperable, por lo que no lo eliminaré todavía, pero no lo use en el código de producción.


Ok, aquí está el mío

 int max3(int a, int b, int c) { return a * (a > b & a > c) + b * (b > a & b > c) + c * (c > a & c > b); } 

Tenga en cuenta que el uso de & lugar de && evita cualquier código condicional; se basa en el hecho de que > siempre produce 0 o 1. (El código generado para a > b podría implicar saltos condicionales, pero no son visibles desde C.)

 int fast_int_max(int a, int b) { int select= -(a < b); unsigned int b_mask= select, a_mask= ~b_mask; return (a&a_mask)|(b&b_mask); } int fast_int_max3(int a, int b, int c) { return fast_int_max(a, fast_int_max(b, c)); } 

Los operadores con valores booleanos (incluidos <, &&, etc.) normalmente se traducen en operaciones condicionales a nivel de código de máquina, por lo que no cumplen con el espíritu del desafío. Aquí hay una solución que cualquier compilador razonable traduciría a solo instrucciones aritméticas sin saltos condicionales (suponiendo que long tiene más bits que int y ese largo es 64 bits). La idea es que "m" capture y replique el bit de signo de b - a, entonces m es cualquiera de los 1 bits (si a> b) o todos los bits cero (si a <= b). Tenga en cuenta que long se usa para evitar el desbordamiento. Si por alguna razón sabe que b - a no sobrepasa / subfluye, entonces no es necesario el uso de largo.

 int max(int a, int b) { long d = (long)b - (long)a; int m = (int)(d >> 63); return a & m | b & ~m; } int max(int a, int b, int c) { long d; int m; d = (long)b - (long)a; m = (int)(d >> 63); a = a & m | b & ~m; d = (long)c - (long)a; m = (int)(d >> 63); return a & m | c & ~m; } 

Sin condicionales. Solo un elenco para uint. Solución perfecta.

 int abs (a) { return (int)((unsigned int)a); } int max (a, b) { return (a + b + abs(a - b)) / 2; } int min (a, b) { return (a + b - abs(a - b)) / 2; } void sort (int & a, int & b, int & c) { int max = max(max(a,b), c); int min = min(min(a,b), c); int middle = middle = a + b + c - max - min; a = max; b = middle; c = min; } 
 #include "stdafx.h" #include  int main() { int x,y,z; scanf("%d %d %d", &x,&y, &z); int max = ((x+y) + abs(xy)) /2; max = ((max+z) + abs(max-z)) /2; printf("%d ", max); return 0; } 

Puede usar este código para encontrar el mayor de dos:

 max{a,b} = abs(ab)/2 + (a+b)/2 

luego úsala nuevamente para encontrar el tercer número:

 max{a,b,c} = max(a,max(b,c)) 

Observe que esto funciona para números positivos, puede cambiarlo para que también funcione en negativo.

Sin declaraciones condicionales , solo bucles y asignaciones. Y completamente diferente de las respuestas de los demás 🙂

 while (a > b) { while (a > c) { tmp = a; goto finish; } tmp = c; goto finish; } while (b > c) { tmp = b; goto finish; } tmp = c; finish: max = tmp; 
 int compare(int a,int b, intc) { return (a > b ? (a > c ? a : c) : (b > c ? b : c)) } 

Prueba esto.

 #include "stdio.h" main() { int a,b,c,rmvivek,arni,csc; printf("enter the three numbers"); scanf("%d%d%d",&a,&b,&c); printf("the biggest value is %d",(a>b&&a>c?a:b>c?b:c)); } 
 max = a > b ? ( a > c ? a : c ) : ( b > c ? b : c ) ;