it-swarm-pt.tech

Maneira mais simples de verificar se dois números inteiros têm o mesmo sinal?

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?

60
Gerber

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

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

Claro, você pode dar uma olhada e criar um modelo:

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

Nota: Como estamos usando exclusive ou, queremos que o LHS e o RHS sejam diferentes quando os sinais forem os mesmos, portanto, a verificação diferente será zero.

47
Torlack

O que há de errado com

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

?

203
Rik
(a ^ b) >= 0

avaliará 1 se o sinal for o mesmo, 0 caso contrário.

23
Chris Jobson

Eu seria cauteloso com quaisquer truques bit a bit para determinar o sinal de números inteiros, pois você deve fazer suposições sobre como esses números são representados internamente.

Quase 100% do tempo, os números inteiros serão armazenados como complemento de 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.

Como complemento de dois, você pode apenas verificar o último bit (mais à esquerda) no 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 a função de sinal do idioma escolhido. É improvável que haja problemas de desempenho com um cálculo como esse.

12
SpoonMeiser

Supondo ints de 32 bits:

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

Um pouco mais conciso:

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

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

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

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

Se os sinais são opostos, você fica falso. Se os sinais são os mesmos, você se torna verdadeiro.

5
OwenP

(inteiro1 * inteiro2)> 0

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

Você também pode torná-lo> = 0 se quiser tratar 0 como sendo o mesmo sinal, não importa o quê.

4
Benjamin Autin

Supondo que dois complementem a aritmética ( 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 que dois complementem a aritmética:

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 péssima idéia, pois é vulnerável ao estouro.

4
user10315

se (x * y)> 0 ...

assumindo diferente de zero e tal.

3
Yes - that Jake.

Como nota técnica, as soluções bit-twiddly serão muito mais eficientes do que a multiplicação, mesmo nas arquiteturas modernas. Você economiza apenas três ciclos, mas sabe o que dizem sobre um "centavo economizado" ...

2
Daniel Spiewak

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));
}
1
CAFxX

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

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

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
1
Mark Ransom

assumindo 32 bits

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

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

1
ugasoft

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

0
dogfish

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

Eu imagino que isso seja bastante dependente da máquina.

0
Dana

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

if (same_sign) ... mais ...

0
andrew

Melhor maneira de usar std :: signbit da seguinte maneira:

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

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

0
ashiquzzaman33