Calcula el máximo de dos números. No debe utilizar if-else ni ningún otro operador de comparación. Encontré esta pregunta en el tablón de anuncios en línea, así que pensé que debería preguntar en StackOverflow
EJEMPLO Entrada: 5, 10 Salida: 10
Encontré esta solución, ¿alguien puede ayudarme a comprender estas líneas de código?
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
<
.Respuestas:
int getMax(int a, int b) { int c = a - b; int k = (c >> 31) & 0x1; int max = a - k * c; return max; }
Analicemos esto. Esta primera línea parece sencilla: almacena la diferencia de
a
yb
. Este valor es negativo sia < b
y no es negativo en caso contrario. En realidad hay un error aquí - si la diferencia de los númerosa
yb
es tan grande que no puede caber en un entero, esto dará lugar a un comportamiento indefinido - ¡Uy! Así que supongamos que eso no sucede aquí.En la siguiente línea, que es
int k = (c >> 31) & 0x1;
la idea es comprobar si el valor de
c
es negativo. En prácticamente todas las computadoras modernas, los números se almacenan en un formato llamado complemento a dos en el que el bit más alto del número es 0 si el número es positivo y 1 si el número es negativo. Además, la mayoría de las entradas son de 32 bits.(c >> 31)
desplaza el número 31 bits hacia abajo, dejando el bit más alto del número en el lugar del bit más bajo. El siguiente paso de tomar este número y anotarlo con 1 (cuya representación binaria es 0 en todas partes excepto el último bit) borra todos los bits más altos y solo le da el bit más bajo. Dado que el bit más bajo dec >> 31
es el bit más alto dec
, esto lee el bit más alto dec
como 0 o 1. Dado que el bit más alto es 1 sifc
es 1, esta es una forma de verificar sic
es negativo (1) o positivo (0). Combinando este razonamiento con el anterior,k
es 1 sia < b
y es 0 en caso contrario.El paso final es hacer esto:
int max = a - k * c;
Si
a < b
, entoncesk == 1
yk * c = c = a - b
, y asíCuál es el máximo correcto, ya que
a < b
. De lo contrario, sia >= b
, entoncesk == 0
ya - k * c = a - 0 = a
Que es también el máximo correcto.
fuente
max = a + (c >> 31) * c
Aquí vamos:
(a + b) / 2 + |a - b| / 2
fuente
(3 + 2) / 2 + |3 - 2| / 2 = 2 + 0 = 2 != 3
.Utilice trucos bit a bit
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
Si sabe eso
INT_MIN <= x - y <= INT_MAX,
, puede usar lo siguiente, que es más rápido porque(x - y)
solo necesita ser evaluado una vez.r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)
Fuente: Bit Twiddling Hacks por Sean Eron Anderson
fuente
(sqrt( a*a + b*b - 2*a*b ) + a + b) / 2
Esto se basa en la misma técnica que la solución de mike.dld , pero es menos "obvio" aquí lo que estoy haciendo. Una operación "abs" parece que está comparando el signo de algo, pero aquí estoy aprovechando el hecho de que sqrt () siempre le devolverá la raíz cuadrada positiva, por lo que estoy elevando al cuadrado (ab) escribiéndolo en su totalidad y luego en cuadrado. enraizándolo nuevamente, agregando a + by dividiendo por 2.
Verá que siempre funciona: por ejemplo, el ejemplo del usuario de 10 y 5 obtiene sqrt (100 + 25 - 100) = 5, luego suma 10 y 5 le da 20 y dividir por 2 le da 10.
Si usamos 9 y 11 como números, obtendríamos (sqrt (121 + 81-198) + 11 + 9) / 2 = (sqrt (4) + 20) / 2 = 22/2 = 11
fuente
La respuesta más simple está a continuación.
#include <math.h> int Max(int x, int y) { return (float)(x + y) / 2.0 + abs((float)(x - y) / 2); } int Min(int x, int y) { return (float)(x + y) / 2.0 - abs((float)(x - y) / 2); }
fuente
int max(int i, int j) { int m = ((i-j) >> 31); return (m & j) + ((~m) & i); }
Esta solución evita la multiplicación. m será 0x00000000 o 0xffffffff
fuente
Usando la idea cambiante para extraer el letrero publicado por otros, aquí hay otra forma:
max (a, b) = new[] { a, b } [((a - b) >> 31) & 1]
Esto empuja los dos números a una matriz con el número máximo dado por el elemento de matriz cuyo índice es el bit de signo de la diferencia entre los dos números.
Tenga en cuenta que:
(a - b
) puede desbordarse.>>
operador se refiere a un desplazamiento lógico a la derecha, no& 1
es necesario.fuente
Así es como creo que haría el trabajo. No es tan legible como te gustaría, pero cuando comienzas con "cómo hago X sin usar la forma obvia de hacer X, tienes que esperar eso. En teoría, esto también renuncia a cierta portabilidad, pero tú" Tendría que encontrar un sistema bastante inusual para ver un problema.
#define BITS (CHAR_BIT * sizeof(int) - 1) int findmax(int a, int b) { int rets[] = {a, b}; return rets[unsigned(a-b)>>BITS]; }
Esto tiene algunas ventajas sobre el que se muestra en la pregunta. En primer lugar, calcula el tamaño correcto de desplazamiento, en lugar de estar codificado para entradas de 32 bits. En segundo lugar, con la mayoría de los compiladores podemos esperar que toda la multiplicación ocurra en el momento de la compilación, por lo que todo lo que queda en el tiempo de ejecución es una manipulación trivial de bits (restar y cambiar) seguida de una carga y un retorno. En resumen, es casi seguro que esto sea bastante rápido, incluso en el microcontrolador más pequeño, donde el original usaba una multiplicación que tenía que ocurrir en tiempo de ejecución, por lo que aunque probablemente sea bastante rápido en una máquina de escritorio, a menudo será bastante un poco más lento en un pequeño microcontrolador.
fuente
Esto es lo que hacen esas líneas:
c es ab. si c es negativo, a <b.
k es el bit 32 de c, que es el bit de signo de c (asumiendo enteros de 32 bits. Si se hace en una plataforma con enteros de 64 bits, este código no funcionará). Se ha desplazado 31 bits hacia la derecha para eliminar los 31 bits más a la derecha, dejando el bit de signo en el lugar más a la derecha y luego anularlo con 1 para eliminar todos los bits a la izquierda (que se llenarán con 1 si c es negativo). Entonces k será 1 si c es negativo y 0 si c es positivo.
Entonces max = a - k * c. Si c es 0, esto significa a> = b, entonces max es a - 0 * c = a. Si c es 1, esto significa que a <b y luego a - 1 * c = a - (a - b) = a - a + b = b.
En general, solo se usa el bit de signo de la diferencia para evitar usar operaciones mayor o menor que. Honestamente, es un poco tonto decir que este código no usa una comparación. c es el resultado de comparar ay b. El código simplemente no usa un operador de comparación. Podría hacer algo similar en muchos códigos de ensamblaje simplemente restando los números y luego saltando según los valores establecidos en el registro de estado.
También debo agregar que todas estas soluciones suponen que los dos números son enteros. Si son flotantes, dobles o algo más complicado (BigInts, números racionales, etc.) entonces realmente tienes que usar un operador de comparación. Los trucos de bits generalmente no sirven para esos.
fuente
Función getMax () sin ninguna operación lógica
int getMax(int a, int b){ return (a+b+((a-b)>>sizeof(int)*8-1|1)*(a-b))/2; }
Explicación:
Vamos a romper el 'máximo' en pedazos,
max = ( max + max ) / 2 = ( max + (min+differenceOfMaxMin) ) / 2 = ( max + min + differenceOfMaxMin ) / 2 = ( max + min + | max - min | ) ) / 2
Entonces la función debería verse así:
getMax(a, b) = ( a + b + absolute(a - b) ) / 2
Ahora,
absolute(x) = x [if 'x' is positive] or -x [if 'x' is negative] = x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
Entonces,
absolute(x) = x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] ) = x * ( ( x >> (numberOfBitsInInteger-1) ) | 1 ) = x * ( ( x >> ((numberOfBytesInInteger*bitsInOneByte) - 1) ) | 1 ) = x * ( ( x >> ((sizeOf(int)*8) - 1) ) | 1 )
Finalmente,
getMax(a, b) = ( a + b + absolute(a - b) ) / 2 = ( a + b + ((a-b) * ( ( (a-b) >> ((sizeOf(int)*8) - 1) ) | 1 )) ) / 2
Otra forma -
int getMax(int a, int b){ int i[] = {a, b}; return i[( (i[0]-i[1]) >> (sizeof(int)*8 - 1) ) & 1 ]; }
fuente
estático int mymax (int a, int b)
{ int[] arr; arr = new int[3]; arr[0] = b; arr[1] = a; arr[2] = a; return arr[Math.Sign(a - b) + 1]; }
Si b> a entonces (ab) será negativo, el signo devolverá -1, al sumar 1 obtenemos el índice 0 que es b, si b = a entonces ab será 0, +1 dará 1 índice por lo que no importa si devolvemos aob, cuando a> b entonces ab será positivo y el signo devolverá 1, sumando 1 obtenemos el índice 2 donde se almacena a.
fuente
#include<stdio.h> main() { int num1,num2,diff; printf("Enter number 1 : "); scanf("%d",&num1); printf("Enter number 2 : "); scanf("%d",&num2); diff=num1-num2; num1=abs(diff); num2=num1+diff; if(num1==num2) printf("Both number are equal\n"); else if(num2==0) printf("Num2 > Num1\n"); else printf("Num1 > Num2\n"); }
fuente
El código que proporciono es para encontrar el máximo entre dos números, los números pueden ser de cualquier tipo de datos (entero, flotante). Si los números de entrada son iguales, la función devuelve el número.
double findmax(double a, double b) { //find the difference of the two numbers double diff=a-b; double temp_diff=diff; int int_diff=temp_diff; /* For the floating point numbers the difference contains decimal values (for example 0.0009, 2.63 etc.) if the left side of '.' contains 0 then we need to get a non-zero number on the left side of '.' */ while ( (!(int_diff|0)) && ((temp_diff-int_diff)||(0.0)) ) { temp_diff = temp_diff * 10; int_diff = temp_diff; } /* shift the sign bit of variable 'int_diff' to the LSB position and find if it is 1(difference is -ve) or 0(difference is +ve) , then multiply it with the difference of the two numbers (variable 'diff') then subtract it with the variable a. */ return a- (diff * ( int_diff >> (sizeof(int) * 8 - 1 ) & 1 )); }
Descripción
El bit de signo se guarda como el bit más significativo (MSB) en la memoria. Si MSB es 1 y viceversa. Para comprobar si MSB es 1 o 0, cambiamos el MSB a la posición LSB y Bitwise & con 1, si el resultado es 1, entonces el número es -ve en caso contrario no. es + ve. Este resultado se obtiene mediante el enunciado:
int_diff >> (tamaño de (int) * 8 - 1) & 1
Aquí, para obtener el bit de signo del MSB al LSB, lo cambiamos a la derecha a k-1 bits (donde k es el número de bits necesarios para guardar un número entero en la memoria que depende del tipo de sistema). Aquí k = sizeof (int) * 8 ya que sizeof () da el número de bytes necesarios para guardar un entero para obtener no. de bits, lo multiplicamos por 8. Después del desplazamiento a la derecha, aplicamos el bit a bit & con 1 para obtener el resultado.
Ahora, después de obtener el resultado (supongamos que es r) como 1 (para -ve diff) y 0 (para + ve diff) multiplicamos el resultado con la diferencia de los dos números, la lógica se da de la siguiente manera:
Ahora quedan dos puntos restantes: 1. el uso del bucle while y 2. por qué he usado la variable 'int_diff' como un número entero. Para responder a estas correctamente debemos entender algunos puntos:
fuente
Aquí hay un par de métodos de alteración de bits para obtener el máximo de dos valores integrales:
Método 1
int max1(int a, int b) { static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1; int mask = (a - b) >> SIGN_BIT_SHIFT; return (a & ~mask) | (b & mask); }
Explicación:
a > b
entoncesa - b
es positivo, entonces el bit de signo es0
y la máscara es0x00.00
. Dea < b
lo contrario, tambiéna - b
es negativo, el bit de signo es1
y después de cambiar, obtenemos una máscara de0xFF..FF
0xFF..FF
, entonces~mask
es0x00..00
y entonces este valor es0
. De lo contrario,~mask
es0xFF..FF
y el valor esa
0xFF..FF
, este valor esb
. De lo contrario,mask
es0x00..00
y el valor es0
.Finalmente:
a >= b
entoncesa - b
es positivo, obtenemosmax = a | 0 = a
a < b
entoncesa - b
es negativo, obtenemosmax = 0 | b = b
Método 2
int max2(int a, int b) { static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1; int mask = (a - b) >> SIGN_BIT_SHIFT; return a ^ ((a ^ b) & mask); }
Explicación:
a > b
la máscara es0x00..00
, de lo contrario, la máscara0xFF..FF
0x00..00
, entonces(a ^ b) & mask
es0x00..00
0xFF..FF
, entonces(a ^ b) & mask
esa ^ b
Finalmente:
a >= b
obtenemosa ^ 0x00..00 = a
a < b
obtenemosa ^ a ^ b = b
fuente
// En C # puede usar la biblioteca matemática para realizar la función mínima o máxima
usando el sistema;
class NumberComparator {
static void Main() { Console.Write(" write the first number to compare: "); double first_Number = double.Parse(Console.ReadLine()); Console.Write(" write the second number to compare: "); double second_Number = double.Parse(Console.ReadLine()); double compare_Numbers = Math.Max(first_Number, second_Number); Console.Write("{0} is greater",compare_Numbers); }
}
fuente
Sin operadores lógicos, sin bibliotecas (JS)
function (x, y) { let z = (x - y) ** 2; z = z ** .5; return (x + y + z) / 2 }
fuente
La lógica descrita en un problema se puede explicar como si el primer número es menor, entonces se restará 0, de lo contrario se restará la diferencia del primer número para obtener el segundo número. Encontré una solución matemática más que creo que es un poco más simple de entender este concepto.
Considerando a y b como números dados
c=|a/b|+1; d=(c-1)/b; smallest number= a - d*(a-b);
Nuevamente, la idea es encontrar k que sea 0 o 1 y multiplicarlo con la diferencia de dos números. Y finalmente este número debe restarse del primer número para obtener el menor de los dos números. PD: esta solución fallará en caso de que el segundo número sea cero
fuente
Hay una forma
public static int Min(int a, int b) { int dif = (int)(((uint)(a - b)) >> 31); return a * dif + b * (1 - dif); }
y uno
return (a>=b)?b:a;
fuente
int a=151; int b=121; int k=Math.abs(a-b); int j= a+b; double k1=(double)(k); double j1= (double) (j); double c=Math.ceil(k1/2) + Math.floor(j1/2); int c1= (int) (c); System.out.println(" Max value = " + c1);
fuente
Supongo que podemos simplemente multiplicar los números con sus comparaciones bit a bit, por ejemplo:
int max=(a>b)*a+(a<=b)*b;
fuente