¿Cuál es la forma más sencilla de verificar si dos enteros tienen el mismo signo? ¿Hay algún truco corto a nivel de bits para hacer esto?
Aquí hay una versión que funciona en C/C++ que no se basa en tamaños de enteros o 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 geek out y la plantilla:
template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
return (x >= 0) ^ (y < 0);
}
Nota: Ya que estamos utilizando exclusivo o, queremos que el LHS y el RHS sean diferentes cuando los signos sean los mismos, por lo tanto, el cheque diferente contra cero.
Qué hay de malo en
return ((x<0) == (y<0));
?
(a ^ b) >= 0
evaluará a 1 si el signo es el mismo, 0 en caso contrario.
Sería cauteloso con cualquier truco a nivel de bits para determinar el signo de los enteros, ya que entonces hay que hacer suposiciones sobre cómo se representan internamente esos números.
Casi el 100% del tiempo, los enteros se almacenarán como cumplido de dos , pero no es una buena práctica hacer suposiciones sobre las partes internas de un sistema a menos que esté usando un tipo de datos que garantice un formato de almacenamiento particular.
Como complemento a dos, solo puede marcar el último bit (el más a la izquierda) en el entero para determinar si es negativo, por lo que puede comparar solo estos dos bits. Esto significaría que 0 tendría el mismo signo como un número positivo, lo cual está en desacuerdo con la función de signo implementada en la mayoría de los idiomas.
Personalmente, solo uso la función de signo de su idioma elegido. Es poco probable que haya problemas de rendimiento con un cálculo como este.
Suponiendo 32 bits bit:
bool same = ((x ^ y) >> 31) != 1;
Un poco más terso:
bool same = !((x ^ y) >> 31);
No estoy realmente seguro de considerar "truco a nivel de bits" y "más simple". Veo muchas respuestas que asumen enteros de 32 bits con signo (aunque sería sería una tontería pedir un signo sin signo); 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 asumiendo que los tipos pueden ser comparados:
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 verdad.
(integer1 * integer2)> 0
Porque cuando dos enteros comparten un signo, el resultado de la multiplicación siempre será positivo.
También puede hacerlo> = 0 si quiere tratar a 0 como si fuera el mismo signo sin importar qué.
Suponiendo que la aritmética se complementa con dos ( http://en.wikipedia.org/wiki/Two_complement ):
inline bool same_sign(int x, int y) {
return (x^y) >= 0;
}
Esto puede tomar tan poco como dos instrucciones y menos de 1 ns en un procesador moderno con optimización.
No asumiendo dos aritmética complementaria:
inline bool same_sign(int x, int y) {
return (x<0) == (y<0);
}
Esto puede requerir una o dos instrucciones adicionales y demorar un poco más.
Usar la multiplicación es una mala idea porque es vulnerable al desbordamiento.
si (x * y)> 0 ...
suponiendo que no es cero y tal.
Como nota técnica, las soluciones de bit twiddly serán mucho más eficientes que la multiplicación, incluso en arquitecturas modernas. Está ahorrando solo 3 ciclos, pero ya sabe lo que dicen sobre un "centavo ahorrado" ...
versión sin sucursales en C:
int sameSign(int a, int b) {
return ~(a^b) & (1<<(sizeof(int)*8-1));
}
Plantilla de C++ para tipos enteros:
template <typename T> T sameSign(T a, T b) {
return ~(a^b) & (1<<(sizeof(T)*8-1));
}
Justo al lado de la parte superior de mi cabeza...
int mask = 1 << 31;
(a & mask) ^ (b & mask) < 0;
Para cualquier tamaño de int con aritmética de complemento a dos:
#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
// signs are the same
suponiendo 32 bits
if(((x^y) & 0x80000000) == 0)
... la respuesta if(x*y>0)
es mala debido al desbordamiento
si el signo (a * b <0) es diferente, el signo de lo contrario es el mismo (o a o b es cero)
Pensando en mis días de universidad, en la mayoría de las representaciones de máquinas, ¿no es el bit más a la izquierda de un número entero a 1 cuando el número es negativo, y 0 cuando es positivo?
Sin embargo, me imagino que esto depende de la máquina.
int same_sign =! ((x >> 31) ^ (y >> 31));
if (same_sign) ... else ...
Mejor manera de usar std :: signbit de la siguiente manera:
std::signbit(firstNumber) == std::signbit(secondNumber);
También es compatible con otros tipos básicos (double
, float
, char
etc).