2010-09-16 28 views
5

Usando operadores bit a bit y supongo que suma y resta, ¿cómo puedo verificar si un entero con signo es positivo (específicamente, no negativo y no cero)? Estoy seguro de que la respuesta a esto es muy simple, pero simplemente no me viene a la mente.¿Cómo puedo verificar si un entero con signo es positivo?

+2

Solo un pensamiento: las respuestas a continuación son buenas, pero creo que no debe usarlas en la práctica porque en una CPU moderna, una comparación como "> 0" es solo 1 instrucción, y cualquiera de las respuestas a continuación van a ser instrucciones múltiples, posiblemente no haciendo uso de tuberías o núcleos separados. Son útiles si está haciendo su propio circuito para una comparación especial y necesita reducir el retraso de la ruta lógica. – Phil

+0

Esto podría ser una pregunta de tarea que limita específicamente el uso de tales comparaciones :) – Alex

+0

está relacionado con un problema de tarea más grande, esta es solo una parte que no puedo entender – Rowhawn

Respuesta

4

Si realmente quiere un "es estrictamente positivo" predicado para el int n sin utilizar los condicionales (suponiendo complemento a 2):

  • -n tendrá el signo (arriba) bit igual si n era estrictamente positivo, y claro en todos los demás casos excepton == INT_MIN;
  • ~n tendrán el bit de signo establece si n era estrictamente positivo o 0, y claro en todos los demás casos, incluyendo n == INT_MIN;
  • ... así que -n & ~n tendrá el bit de signo establecido si n fue estrictamente positivo, y claro en todos los demás casos.

Aplicar una sin firmar cambio a convertir esto en un 0/1 respuesta:

int strictly_positive = (unsigned)(-n & ~n) >> ((sizeof(int) * CHAR_BIT) - 1); 

EDIT: como puntos de CAF en los comentarios, -n provoca un desbordamiento cuando n == INT_MIN (aún asumiendo complemento a 2) El estándar C permite que el programa falle en este caso (por ejemplo, puede habilitar capturas para desbordamiento firmado usando GCC con la opción -ftrapv). Casting n a unsigned corrige el problema (la aritmética sin signo no causa desbordamientos). Así que una mejora sería:

unsigned u = (unsigned)n; 
int strictly_positive = (-u & ~u) >> ((sizeof(int) * CHAR_BIT) - 1); 
+0

gracias, esto realmente me ayudó a llegar a lo que quería – Rowhawn

+0

'-n' puede desbordarse en el caso de' n == INT_MIN'. – caf

+0

Estrictamente, eso solo funciona en la aritmética de complemento de 2 (que son, les garantizo, los sistemas prácticamente significativos). Con un cero negativo (complemento de 1 o magnitud de signo), sus afirmaciones no son válidas. –

3

Comprueba el bit más significativo. 0 es positivo, 1 es negativo.

+1

Esto falla para cero, que no es ni positivo ni negativo. – caf

+0

Pero si el bit más significativo es 0 y todos los demás bits son cero, devuelve 'positivo' pero se supone que se excluirá el cero. –

+0

Tiene razón, aunque podría verificar si hay alguno == 0; – Alex

1

Considere cómo se representa la firma. A menudo se hace con complemento de dos o con un simple bit de signo - Creo que ambos podrían verificarse con un simple y lógico.

0

Compruebe que no es 0 y el bit más significativo es 0, algo así como:

int positive(int x) { 
    return x && (x & 0x80000000); 
} 
+0

Asumiendo sizeof (int) == 4 ... –

+0

¿Qué tal el retorno x && (x & MIN_INT)? – Ssancho

3

Si no puede utilizar los operadores de comparación obvios, entonces usted tiene que trabajar más duro:

int i = anyValue; 
if (i && !(i & (1U << (sizeof(int) * CHAR_BIT - 1)))) 
    /* I'm almost positive it is positive */ 

El primer término verifica que el valor no sea cero; el segundo verifica que el valor no tenga el bit inicial establecido. Eso debería funcionar para enteros de 2's, complementos de 1 o enteros de magnitud de signo.

+0

Desafortunadamente, tiene un comportamiento indefinido;) - 2 elevado a la potencia de '(sizeof (int) * CHAR_BIT - 1)' ciertamente no es representable en 'int'. – caf

+0

@caf: eso se puede resolver convirtiendo el 1 que se desplaza a 'unsigned int' con un sufijo U ... lo que significa que' i' también se convertirá en 'unsigned int'. El cambio de bit normalmente debería hacerse en cantidades sin signo de todos modos. –

+0

Sí, eso arregla el UB - ahora solo tiene que preocuparse por el caso (¡incluso más teórico!) Donde 'int' y' unsigned int' tienen el mismo número de bits de valor ... – caf

Cuestiones relacionadas