Pergunta

Qual é a maneira mais simples de verificar se dois números inteiros têm o mesmo sinal?Existe algum truque bit a bit para fazer isso?

Foi útil?

Solução

Aqui está uma versão que funciona em C/C++ que não depende de tamanhos inteiros ou tem o problema de overflow (ou seja,x*y>=0 não funciona)

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

Claro, você pode criar um modelo:

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

Observação:Como estamos usando ou exclusivo, queremos que LHS e RHS sejam diferentes quando os sinais forem iguais, portanto, a verificação diferente em relação a zero.

Outras dicas

O que há de errado com

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

?

(a ^ b) >= 0

será avaliado como 1 se o sinal for o mesmo, 0 caso contrário.

Eu ficaria cauteloso com qualquer truque bit a bit para determinar o sinal de números inteiros, pois então você terá que fazer suposições sobre como esses números são representados internamente.

Quase 100% do tempo, os números inteiros serão armazenados como elogio a dois, mas não é uma boa prática fazer suposições sobre os componentes internos de um sistema, a menos que você esteja usando um tipo de dados que garanta um formato de armazenamento específico.

No elogio de dois, você pode apenas verificar o último bit (mais à esquerda) do número inteiro para determinar se é negativo, para poder comparar apenas esses dois bits.Isso significaria que 0 teria o mesmo sinal que um número positivo, o que está em desacordo com a função de sinal implementada na maioria dos idiomas.

Pessoalmente, eu usaria apenas a função de sinal do idioma escolhido.É improvável que haja problemas de desempenho com um cálculo como este.

Supondo entradas de 32 bits:

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

Um pouco mais conciso:

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

Não tenho certeza se consideraria "truque bit a bit" e "mais simples" sinônimos.Vejo muitas respostas que assumem números inteiros assinados de 32 bits (embora seria seja bobo em pedir sem assinatura);Não tenho certeza se eles se aplicariam a valores de ponto flutuante.

Parece que a verificação "mais simples" seria comparar como ambos os valores se comparam a 0;isso é bastante genérico, assumindo que os tipos podem ser comparados:

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

Se os sinais forem opostos, você será falso.Se os sinais forem iguais, você acerta.

(inteiro1 * inteiro2) > 0

Porque quando dois inteiros compartilham um sinal, o resultado da multiplicação será sempre positivo.

Você também pode definir >= 0 se quiser tratar 0 como sendo o mesmo sinal, não importa o que aconteça.

Supondo a aritmética do complemento de dois (http://en.wikipedia.org/wiki/Two_complement):

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

Isso pode levar apenas duas instruções e menos de 1ns em um processador moderno com otimização.

Não assumindo a aritmética do complemento de dois:

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

Isso pode exigir uma ou duas instruções extras e demorar um pouco mais.

Usar a multiplicação é uma má ideia porque é vulnerável ao estouro.

se (x * y) > 0...

assumindo diferente de zero e tal.

Como observação técnica, soluções pouco complicadas serão muito mais eficientes do que a multiplicação, mesmo em arquiteturas modernas.São apenas cerca de 3 ciclos que você está economizando, mas você sabe o que dizem sobre um "centavo economizado"...

Apenas fora do topo da minha cabeça...

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

versão C sem ramificação:

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

Modelo C++ para tipos inteiros:

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

Para qualquer tamanho de int com aritmética de complemento de dois:

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

assumindo 32 bits

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

...a resposta if(x*y>0) está ruim devido ao transbordamento

se o sinal (a*b < 0) for diferente, caso contrário o sinal será o mesmo (ou a ou b for zero)

Pensando nos meus tempos de universidade, na maioria das representações de máquinas, o bit mais à esquerda de um número inteiro não é 1 quando o número é negativo e 0 quando é positivo?

Imagino que isso dependa bastante da máquina.

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

se (mesmo_sinal) ...outro ...

Melhor maneira de usar std::signbit do seguinte modo:

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

Ele também oferece suporte a outros tipos básicos (double, float, char etc).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top