Pregunta

¿Cuál es la forma más sencilla de comprobar si dos números enteros tienen el mismo signo?¿Existe algún truco breve bit a bit para hacer esto?

¿Fue útil?

Solución

Aquí hay una versión que funciona en C/C++ y que no depende de tamaños enteros ni tiene el problema de desbordamiento (es decir,x*y>=0 no funciona)

bool SameSign(int x, int y)
{
    return (x >= 0) ^ (y < 0);
}

Por supuesto, puedes divertirte y crear plantillas:

template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
    return (x >= 0) ^ (y < 0);
}

Nota:Dado que estamos usando exclusivo o, queremos que el LHS y el RHS sean diferentes cuando los signos son los mismos, por lo que la verificación diferente es cero.

Otros consejos

Qué hay de malo en

return ((x<0) == (y<0));  

?

(a ^ b) >= 0

se evaluará como 1 si el signo es el mismo, 0 en caso contrario.

Yo desconfiaría de cualquier truco bit a bit para determinar el signo de los números enteros, ya que entonces hay que hacer suposiciones sobre cómo se representan esos números internamente.

Casi el 100% de las veces, los números enteros se almacenarán como elogio de dos, pero no es una buena práctica hacer suposiciones sobre los aspectos internos de un sistema a menos que esté utilizando un tipo de datos que garantice un formato de almacenamiento particular.

En el complemento de dos, puedes simplemente verificar el último bit (el más a la izquierda) del número entero para determinar si es negativo, de modo que puedas comparar solo estos dos bits.Sin embargo, esto significaría que 0 tendría el mismo signo que un número positivo, lo que está en desacuerdo con la función de signo implementada en la mayoría de los idiomas.

Personalmente, simplemente usaría la función de signos del idioma elegido.Es poco probable que haya problemas de rendimiento con un cálculo como este.

Suponiendo entradas de 32 bits:

bool same = ((x ^ y) >> 31) != 1;

Un poco más conciso:

bool same = !((x ^ y) >> 31);

No estoy realmente seguro de considerar "truco bit a bit" y "más simple" como sinónimos.Veo muchas respuestas que suponen enteros de 32 bits con signo (aunque haría sería tonto pedirlo sin firmar);No estoy seguro de que se apliquen a valores de punto flotante.

Parece que la verificación "más simple" sería comparar cómo ambos valores se comparan con 0;Esto es bastante genérico suponiendo que los tipos se puedan comparar:

bool compare(T left, T right)
{
    return (left < 0) == (right < 0);
}

Si los signos son opuestos, obtienes falso.Si los signos son los mismos, obtienes la verdad.

(entero1 * entero2) > 0

Porque cuando dos números enteros comparten signo, el resultado de la multiplicación siempre será positivo.

También puedes hacerlo >= 0 si quieres tratar 0 como si fuera el mismo signo sin importar nada.

Suponiendo aritmética en complemento a dos (http://en.wikipedia.org/wiki/Two_complement):

inline bool same_sign(int x, int y) {
    return (x^y) >= 0;
}

Esto puede requerir tan solo dos instrucciones y menos de 1 ns en un procesador moderno con optimización.

Sin asumir aritmética en complemento a dos:

inline bool same_sign(int x, int y) {
    return (x<0) == (y<0);
}

Esto puede requerir una o dos instrucciones adicionales y llevar un poco más de tiempo.

Usar la multiplicación es una mala idea porque es vulnerable al desbordamiento.

si (x * y) > 0...

suponiendo distinto de cero y tal.

Como nota técnica, las soluciones de bits serán mucho más eficientes que la multiplicación, incluso en arquitecturas modernas.Son sólo unos 3 ciclos los que estás ahorrando, pero ya sabes lo que dicen sobre un "centavo ahorrado"...

Justo al lado de la parte superior de mi cabeza...

int mask = 1 << 31;
(a & mask) ^ (b & mask) < 0;

versión C sin ramas:

int sameSign(int a, int b) {
    return ~(a^b) & (1<<(sizeof(int)*8-1));
}

Plantilla C++ para tipos de números enteros:

template <typename T> T sameSign(T a, T b) {
    return ~(a^b) & (1<<(sizeof(T)*8-1));
}

Para cualquier tamaño de int con aritmética en complemento a dos:

#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
    // signs are the same

asumiendo 32 bits

if(((x^y) & 0x80000000) == 0)

...la respuesta if(x*y>0) es malo debido al desbordamiento

si el signo (a*b < 0) es diferente, en caso contrario el signo es el mismo (o aob es cero)

Pensando en mis días universitarios, en la mayoría de las representaciones de máquinas, ¿no es el bit entero más a la izquierda un 1 cuando el número es negativo y un 0 cuando es positivo?

Sin embargo, imagino que esto depende bastante de la máquina.

int mismo_signo = !( (x >> 31) ^ (y >> 31) );

si (mismo_signo)...demás ...

Mejor manera de usar std::bit de signo como sigue:

std::signbit(firstNumber) == std::signbit(secondNumber);

También admite otros tipos básicos (double, float, char etc).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top