obtener valor absoluto sin usar la función de abs ni if ​​statement

Estaba pensando en cómo obtener el valor absoluto de un entero sin usar if statement ni abs() . Al principio, estaba usando los bits de cambio a la izquierda ( << ), tratando de obtener un signo negativo fuera del rango, luego los cambié de vuelta a donde estaba, pero desafortunadamente no me funciona. Por favor, hágame saber por qué no funciona y otras formas alternativas de hacerlo.

De los trucos de Bit Twiddling :

 int v; // we want to find the absolute value of v unsigned int r; // the result goes here int const mask = v >> sizeof(int) * CHAR_BIT - 1; r = (v + mask) ^ mask; 
 int abs(int v) { return v * ( (v<0) * (-1) + (v>0)); // simpler: v * ((v>0) - (v<0)) thanks Jens } 

Este código multiplica el valor de v con -1 o 1 para obtener abs (v). Por lo tanto, dentro del paréntesis será uno de -1 o 1 .

Si v es positivo, la expresión (v>0) es verdadera y tendrá el valor 1 mientras que (v<0) es falsa (con un valor 0 para falso). Por lo tanto, cuando v es positivo ((v>0) - (v<0)) = (1-0) = 1 . Y toda la expresión es: v * (1) == v .

Si v es negativo, la expresión (v>0) es falsa y tendrá el valor 0 mientras que (v<0) es verdadera (valor 1). Por lo tanto, para v negativa, ((v>0) - (v<0)) = (0-1) = -1 . Y toda la expresión es: v * (-1) == -v .

Cuando v == 0 , tanto (v<0) como (v>0) se evaluarán como 0, dejando: v * 0 == 0 .

Sin twigs * :

 int abs (int n) { const int ret[2] = { n, -n }; return ret [n<0]; } 

Nota 4.7 Conversiones integrales / 4: [...] If the source type is bool, the value false is converted to zero and the value true is converted to one.


* : En el sentido de que no hay bifurcaciones condicionales en su código. Bajo el capó, el operador ternario también producirá una twig. Sin embargo, también es una respuesta válida, porque la ternaria no es una sentencia if. Esto no implica que su comstackdor no pueda emitir código de ensamblaje sin ramificación para el código que lógicamente se ramifica.

Suponiendo enteros con signo de 32 bits (Java), puede escribir:

 public static int abs(int x) { return (x + (x >> 31)) ^ (x >> 31); } 

Sin multiplicación, sin twig.

Por cierto, return (x ^ (x >> 31)) - (x >> 31); Funcionaría igual pero está patentado. ¡Sip!

Nota: este código puede tardar más de 10 veces más que la statement condicional (8bit Verison). Esto puede ser útil para la progtwigción de hardware del sistema C, etc.

Los enteros con signo de cambio de bits en la forma que consideras es un comportamiento indefinido y por lo tanto no es una opción. En su lugar, puede hacer esto:

 int abs(int n) { return n > 0 ? n : -n; } 

No if declaraciones if , solo una expresión condicional.

Intento este código en C, y funciona.

 int abs(int n){ return n*((2*n+1)%2); } 

Espero que esta respuesta sea de ayuda.

Intenta lo siguiente:

 int abs(int n) { return sqrt(n*n); } 

Aquí hay otro enfoque sin abs() , si ni ninguna expresión lógica / condicional: supongamos que int es un entero de 32 bits aquí. La idea es bastante simple: (1 - 2 * sign_bit) convertirá sign_bit = 1 / 0 to -1 / 1 .

 unsigned int abs_by_pure_math( int a ) { return (1 - (((a >> 31) & 0x1) << 1)) * a; } 

No vi este. Para la representación de complemento a dos y 32 bit int.

 ( n >> 31 | 1 ) * n 

Si su idioma permite bool to int (C / C ++ like):

 float absB(float n) { return n - n * 2.0f * ( n < 0.0f ); } 

Utilice el operador ternario:

 y = condition ? value_if_true : value_if_false; 

Qué hay sobre eso:

 value = value > 0 ? value: ~value + 1 

se basa en el hecho de que los números negativos se almacenan como complemento de 2 a su equivalente positivo, y que uno puede construir el complemento de 2 al construir primero el complemento de 1 y sumr 1, por lo que

  5 -> 0000 0101b -5 -> (1111 1010b) + 1 -> 1111 1011b 

Lo que hice fue básicamente revertir esto, así que

 -5 -> 1111 1011b 5 -> (0000 0100b) + 1 -> 0000 0101b 

Sé que es un poco tarde, pero tuve el mismo problema y aterrizó aquí, espero que esto ayude.

Hay varias razones por las que se deja a la izquierda el desplazamiento del signo y el desplazamiento a la derecha en su lugar ( v << 1 >> 1 ):

  • el desplazamiento a la izquierda de un tipo firmado con un valor negativo tiene un comportamiento indefinido, por lo que no debe utilizarse en absoluto.
  • convertir el valor a unsigned tendría el efecto deseado: (unsigned)v << 1 >> 1 elimina el bit de signo, si no hay bits de relleno, pero el valor resultante es el valor absoluto de v solo en sistemas con Signo + representación en magnitud, que son muy poco comunes hoy en día. En la architecture de complemento de la ubicua 2, el valor resultante para v negativo es INT_MAX+1-v

La solución de Hasturkun desafortunadamente tiene un comportamiento de implementación definido.

Aquí hay una variación que está completamente definida para sistemas con representación de complemento 2 para valores firmados:

 int v; // we want to find the absolute value of v unsigned int r; // the result goes here unsigned int mask = -((unsigned int)v >> (sizeof(unsigned int) * CHAR_BIT - 1)); r = ((unsigned int)v + mask) ^ mask; 

Sin twigs ni multiplicación:

 int abs(int n) { int mask = n >> 31; return (mask & -n) | (~mask & n); } 

¿Qué pasa con este?

 #include  long abs (int n) { // we use long to avoid issues with INT MIN value as there is no positive equivalents. const long ret[2] = {n, -n}; return ret[n >> (sizeof(int) * CHAR_BIT - 1)]; // we use the most significant bit to get the right index. } 

Tienes que combinar bitwise y add.

Lo que está mal con solo:

 -1 * n 

Usando el principio de menos menos es igual a más

Si quieres una forma puramente matemática que no sea demasiado costosa, prueba

 f(x) = (x*x)/x 

o en C ++

 function abs(auto x) {return ((x*x)/x);}