2008-09-15 10 views

Respuesta

42

Aquí está una versión que funciona en C/C++ que no se basa en tamaños enteros o tienen el problema de desbordamiento (es decir, x * y> = 0 no funciona)

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

Por supuesto, puede geek y la plantilla:

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

Nota: Puesto que estamos utilizando exclusivo o, queremos que el LHS y el RHS a ser diferentes cuando los signos son iguales, por lo tanto los diferentes cheque contra cero.

+1

Muy bien, el hacker C/C++ en mí es totalmente compatible con este fragmento de código. El ingeniero de software en mí pregunta por qué el usuario necesita saber esto de una manera tan genérica. – user7116

+0

¿Esto no falla si x = 0 e y> 0? –

2

si (x * y)> 0 ...

suponiendo que no sea cero y tal.

1

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

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

sólo funciona durante 32 bits enteros, que no estaba estipulado en la pregunta –

0

si (a * b < 0) signo es diferente, signo demás es igual (o A o B es cero)

+0

No funciona para el desbordamiento –

6

suponiendo 32 ints bits:

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

poco más concisa:

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

Esos dos ejemplos de código deben SIEMPRE SIEMPRE SIEMPRE estar precedidos de un comentario por favor código (en la vida real) –

+3

Oh, por supuesto . En la vida real, probablemente usaría algo como same = Math.Sign (x) == Math.Sign (y). Acabo de dar soluciones diabólicas cuando las personas las piden. : D – Patrick

+1

Um, este código no es válido ... ¿cómo esperas que '& >>' funcione? –

0

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

Supongo que esto es más bien dependiente de la máquina, sin embargo.

4

(entero1 * entero2)> 0

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

También puede hacerlo> = 0 si desea tratar 0 como si fuera el mismo signo pase lo que pase.

+2

Solo funciona hasta que el producto se desborda. – Frosty

+1

también, la multiplicación puede ser bastante lenta ... –

+0

Si uno de los enteros es 0, entonces tienes un problema. – TatiOverflow

0

int same_sign =! ((X >> 31)^(y >> 31));

si (same_sign) ... otra cosa ...

2

Como nota técnica, soluciones de bits twiddly van a ser mucho más eficiente que la multiplicación, incluso en arquitecturas modernas. Es sólo alrededor de 3 ciclos que usted está ahorrando, pero ya sabes lo que dicen de un "centavo ahorrado" ...

+5

un centavo ahorrado es la raíz de todo mal, digamos alrededor del 97% del tiempo? – ysth

18
(a^b) >= 0 

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

+0

¡Oh, bien! :-) Me sorprende que me haya perdido esta. Lo realmente bueno de esta solución es que no depende de una cardinalidad de bit particular en la representación entera subyacente. –

+1

Este da como resultado el encantador y compacto "xorl% edi,% esi; sets% al" en x86, solo 6 bytes y dos instrucciones. También es un estudio de caso interesante, ya que es un caso concreto en el que devolver un 'bool' en lugar de un int produce un código dramáticamente mejor. –

+0

@JohnMeacham: preguntándose a qué se refiere con 'es un caso concreto en el que devolver un' bool 'en lugar de un int produce un código dramáticamente mejor' –

11

Sería cauteloso con cualquier trucos de bit a bit para determinar el signo de los enteros, ya que entonces tiene que hacer suposiciones sobre cómo esos números se representan internamente.

Casi el 100% del tiempo, los enteros se almacenarán como two's compliment, pero no es una buena práctica hacer suposiciones sobre las partes internas de un sistema a menos que esté utilizando un tipo de datos que garantice un formato de almacenamiento particular.

En dos complementos, puede verificar el último bit (el extremo izquierdo) en el número entero para determinar si es negativo, por lo que puede 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, solo usaría la función de signo del idioma elegido. Es poco probable que haya problemas de rendimiento con un cálculo como este.

+0

Además, esos trucos disminuyen la legibilidad. – hop

+1

C Standard Lib proporciona una función signbit(). Probablemente sea difícil vencer al optimizador con cualquier "truco a nivel de bit" que haya ideado. – hop

1

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

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

asumiendo 32 bits

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

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

5

No estoy muy seguro de que consideraría "truco bitwise" y "más simple" también. Veo muchas respuestas que están asumiendo números enteros de 32 bits (aunque sería sería una tontería pedir sin firmar); No estoy seguro de que se apliquen a los valores de coma flotante.

Parece que el control "más simple" sería comparar cómo ambos valores se comparan con 0; esto es bastante genérico suponiendo que los tipos se pueden comparar:

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

Si los signos son opuestos, se obtiene falso. Si los signos son los mismos, te haces verdadero.

+0

falso && false == false Me temo que tendrías que hacer la negación de un XOR para hacerlo correcto. –

187

¿Qué hay de malo en

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

?

+21

Um ... Nada ... Triste que todos perdimos la solución simple. – Torlack

+0

Gran respuesta, la simplicidad es maravillosa. –

+1

¿Qué hay de cero firmado? -0.0 vs cero sin signo 0.0 –

4

dos en dos Suponiendo que complementan la aritmética (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 la optimización.

dos en dos

no asumir complementan la aritmética:

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

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

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

+0

1 y 0 se devuelve verdadero para ambas funciones ... – matias

+1

@matias Como debería. 0 y 1 tienen el mismo signo. Los números enteros no tienen un 0. –

+0

negativo, obviamente tienes razón, estoy totalmente loco por el cerebro – matias

1

sucursales C versión:

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

C++ plantilla para tipos de enteros:

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

mejor manera usando std::signbit como sigue:

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

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

Cuestiones relacionadas