2010-09-23 22 views
25

Puedo verificar si un número es impar/par usando operadores bit a bit. ¿Puedo verificar si un número es positivo/cero/negativo sin utilizar ningún enunciado/operador condicional como if/ternary etc.Comprobando si un número es positivo o negativo usando operadores bit a bit

¿Se puede hacer lo mismo usando operadores bit a bit y algún truco en C o en C++?

+3

¿Cómo se relaciona este 'código de golf'? – meagar

+0

Cuando busca impar/par, es posible que desee hacer una comprobación bit a bit para eliminar la división (en caso de que su compilador sea tan tonto). Pero ** ¿por qué ** para verificar el cartel de esta manera? – ybungalobill

+2

Indique el formato numérico. Enteros? Flotadores? ¿Qué tipo de enteros/carrozas? Complemento de dos? Signo + Magnitud? IEEE-754? Se específico. – sellibitze

Respuesta

14

Si el bit alto se establece en un entero con signo (byte, largo, etc., pero no un número de coma flotante), ese número es negativo.

int x = -2300; // assuming a 32-bit int 

if ((x & 0x80000000) != 0) 
{ 
    // number is negative 
} 

añadido:

Usted dice que usted no desea utilizar ningún condicionales. Supongo que se podría hacer esto:

int isNegative = (x & 0x80000000); 

Y en algún momento posterior se puede probar con if (isNegative).

+5

Los números de coma flotante hoy en día tienden a estar en el formato IEEE, que tiene un bit de signo explícito. –

+0

@David: No lo sabía. ¿Sabes qué bit es el signo? –

+0

@Jim Mischel: de acuerdo con esta página: http://en.wikipedia.org/wiki/Double_precision_floating-point_format, también es el bit alto. –

24

puedo comprobar si un número es positiva/nula/negativa sin el uso de instrucciones condicionales/operadores como si/ternaria etc.

Por supuesto:

bool is_positive = number > 0; 
bool is_negative = number < 0; 
bool is_zero = number == 0; 
+17

Bueno, creo que está preguntando por los operadores bit a bit ... –

+8

En realidad, esta es la única plataforma independiente. Además, será más eficiente que la verificación bit a bit en ** todas ** plataformas. – ybungalobill

+0

Actualmente, * hay * otra plataforma independiente: 'signbit()'. Ver mi respuesta http://stackoverflow.com/a/19279266/72176 para más. –

3

enteros con signo y los puntos flotantes normalmente usan el bit más significativo para almacenar el signo, por lo que si conoce el tamaño, puede extraer la información del bit más significativo.

En general, hay poco beneficio en hacer esto, ya que se necesitará hacer algún tipo de comparación para usar esta información y es tan fácil para un procesador probar si algo es negativo, ya que es probar si es no cero De hecho, en los procesadores ARM, verificar el bit más significativo normalmente será MÁS caro que verificar si es negativo por adelantado.

0

Puede diferenciar entre negativo/no negativo mirando el bit más significativo. En todas las representaciones para enteros con signo, ese bit se establecerá en 1 si el número es negativo.

no existe una prueba para diferenciar entre cero y positiva, a excepción de una prueba directa contra 0.

Para probar la negativa, podría utilizar

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1))) 
+0

El tamaño y el ancho de un tipo entero no están estrictamente relacionados en el sentido que usted está sugiriendo. En segundo lugar, el bit más significativo del tipo sin firmar no es necesariamente el bit de signo: el ancho del tipo firmado correspondiente podría ser más pequeño, o incluso podría ser uno más que el del tipo sin signo. –

+0

@Jens: Pedencialmente hablando, tienes razón y es imposible determinar qué bit contiene el signo. ¿Pero puede nombrar una plataforma en existencia donde este código no funciona? –

+0

Son raros, lo admito, pero existen. Lamentablemente, en alemán, pero es posible que tenga la idea: http://www.schellong.de/c_padding_bits.htm. También en esta discusión hay un ejemplo interesante: http://www.rhinocerus.net/forum/lang-c/2007-padding-bits.html –

11

Hay una discusión detallada sobre la Bit Twiddling Hacks page .

int v;  // we want to find the sign of v 
int sign; // the result goes here 

// CHAR_BIT is the number of bits per byte (normally 8). 
sign = -(v < 0); // if v < 0 then -1, else 0. 
// or, to avoid branching on CPUs with flag registers (IA32): 
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1)); 
// or, for one less instruction (but not portable): 
sign = v >> (sizeof(int) * CHAR_BIT - 1); 

// The last expression above evaluates to sign = v >> 31 for 32-bit integers. 
// This is one operation faster than the obvious way, sign = -(v < 0). This 
// trick works because when signed integers are shifted right, the value of the 
// far left bit is copied to the other bits. The far left bit is 1 when the value 
// is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior 
// is architecture-specific. 

// Alternatively, if you prefer the result be either -1 or +1, then use: 

sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then -1, else +1 

// On the other hand, if you prefer the result be either -1, 0, or +1, then use: 

sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1)); 
// Or, for more speed but less portability: 
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1)); // -1, 0, or +1 
// Or, for portability, brevity, and (perhaps) speed: 
sign = (v > 0) - (v < 0); // -1, 0, or +1 

// If instead you want to know if something is non-negative, resulting in +1 
// or else 0, then use: 

sign = 1^((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1 

// Caveat: On March 7, 2003, Angus Duggan pointed out that the 1989 ANSI C 
// specification leaves the result of signed right-shift implementation-defined, 
// so on some systems this hack might not work. For greater portability, Toby 
// Speight suggested on September 28, 2005 that CHAR_BIT be used here and 
// throughout rather than assuming bytes were 8 bits long. Angus recommended 
// the more portable versions above, involving casting on March 4, 2006. 
// Rohit Garg suggested the version for non-negative integers on September 12, 2009. 
1

Esto no se puede hacer de una manera portátil con operaciones de bits en C. Las representaciones de tipos enteros con signo de que la norma permite que puede ser mucho más raro que se puede sospechar. En particular, el valor con el bit de signo activado y, de lo contrario, cero, no necesita ser un valor permitido para el tipo con signo ni el tipo sin signo, sino una denominada representación de captura para ambos tipos.

Todos los cálculos con operadores de bits que pueda realizar de este modo pueden dar como resultado un comportamiento no definido.


En cualquier caso, ya que algunas de las otras respuestas sugieren, esto no es realmente necesario y la comparación con < o > debería ser suficiente en cualquier contexto práctico, es más eficiente, más fácil de leer ... así que sólo lo hacen de esa manera.

0

Supongamos que su número es a=10 (positivo). Si cambia aa veces dará cero.

es decir:

10>>10 == 0 

para que pueda comprobar si el número es positivo, pero en el caso a=-10 (negativo):

-10>>-10 == -1 

Así que usted puede combinar las de un if:

if(!(a>>a)) 
    print number is positive 
else 
    print no. is negative 
+1

'-10 >> -10' es, creo, lo haré -formado, y '-10 >> 10' es la implementación definida. –

+1

El desplazamiento negativo tiene * comportamiento indefinido * en C. Y si a es mayor que el ancho de int (o el tipo de datos de a), también es un comportamiento indefinido. –

4
#include<stdio.h> 

void main() 
{ 
    int n; // assuming int to be 32 bit long 

    //shift it right 31 times so that MSB comes to LSB's position 
    //and then and it with 0x1 
    if ((n>>31) & 0x1 == 1) { 
     printf("negative number\n"); 
    } else { 
     printf("positive number\n"); 
    } 

    getch(); 
} 
2
// if (x < 0) return -1 
// else if (x == 0) return 0 
// else return 1 
int sign(int x) { 
    // x_is_not_zero = 0 if x is 0 else x_is_not_zero = 1 
    int x_is_not_zero = ((x | (~x + 1)) >> 31) & 0x1; 
    return (x & 0x01 << 31) >> 31 | x_is_not_zero; // for minux x, don't care the last operand 
} 

¡Esto es exactamente lo que quieres!

3

es bastante simple

Se puede hacer fácilmente por

return ((!!x) | (x >> 31)); 

devuelve

  • 1 para un número positivo,
  • -1 para una negativa, y
  • 0 para cero
+0

Suponiendo enteros de 32 bits :) – AndyG

+0

@AndyG 'return ((!! x) | (x >> (8 * sizeof (int) -1)));' sería una mejor manera, creo. – noufal

+0

Cuando evalué esta expresión, para valores negativos de x, devolvió 1 en lugar de -1.Puede corregir mi error: si x = -ve, entonces, (! X) = 0 => (!! x) = 1; x >> 31 = 1; Por lo tanto ((!! x) | (x >> 31)) = (1) | (1) = (1) – piyukr

0

Cuando estás seguro sobre el tamaño de un entero (suponiendo int de 16 bits):

bool is_negative = (unsigned) signed_int_value >> 15; 

Cuando no esté seguro del tamaño de los números enteros:

bool is_negative = (unsigned) signed_int_value >> (sizeof(int)*8)-1; //where 8 is bits 

La palabra clave unsigned es opcional.

1
if((num>>sizeof(int)*8 - 1) == 0) 
    // number is positive 
else 
    // number is negative 

Si el valor es 0, entonces el número es positivo cosa negativa

1

Una forma más sencilla de averiguar si un número es positivo o negativo: Deje que el número sea x verificación si [x * (-1)]> x. si es verdadero x es negativo más positivo.

0

Aquí hay una actualización relacionada con C++ 11 para esta pregunta anterior.También vale la pena considerar std::signbit.

El compilador gcc 7.3 Explorer con 64 bits con la optimización -O3, este código

bool s1(double d) 
{ 
    return d < 0.0; 
} 

genera

s1(double): 
    pxor xmm1, xmm1 
    ucomisd xmm1, xmm0 
    seta al 
    ret 

Y este código

bool s2(double d) 
{ 
    return std::signbit(d); 
} 

genera

s2(double): 
    movmskpd eax, xmm0 
    and eax, 1 
    ret 

Debería tener perfil para asegurarse de que haya una diferencia de velocidad, pero la versión de inicio de sesión usa 1 código de operación menos.

Cuestiones relacionadas