web-dev-qa-db-fra.com

Le moyen le plus simple de vérifier si deux entiers ont le même signe?

Quelle est la manière la plus simple de vérifier si deux entiers ont le même signe? Y a-t-il une astuce au niveau du bit pour le faire?

60
Gerber

Voici une version qui fonctionne en C/C++ qui ne repose pas sur des tailles entières ou qui a le problème de débordement (c'est-à-dire que x * y> = 0 ne fonctionne pas)

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

Bien sûr, vous pouvez geek et modèle:

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

Remarque: Puisque nous utilisons exclusif ou, nous voulons que le LHS et le RHS soient différents lorsque les signes sont les mêmes, donc la vérification différente contre zéro.

47
Torlack

Quel est le problème avec

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

?

203
Rik
(a ^ b) >= 0

sera évalué à 1 si le signe est le même, 0 sinon.

23
Chris Jobson

Je me méfierais de toute astuce au niveau du bit pour déterminer le signe des nombres entiers, car vous devez alors faire des hypothèses sur la façon dont ces nombres sont représentés en interne.

Presque 100% du temps, les entiers seront stockés sous la forme compliment de deux , mais ce n'est pas une bonne pratique de faire des hypothèses sur les composants internes d'un système, sauf si vous utilisez un type de données qui garantit un format de stockage particulier.

Dans le compliment de deux, vous pouvez simplement vérifier le dernier bit (le plus à gauche) de l'entier pour déterminer s'il est négatif, afin que vous puissiez comparer uniquement ces deux bits. Cela signifierait cependant que 0 aurait le même signe qu'un nombre positif, ce qui est en contradiction avec la fonction de signe implémentée dans la plupart des langues.

Personnellement, je n'utiliserais que la fonction de signe de la langue choisie. Il est peu probable qu'il y ait des problèmes de performances avec un calcul comme celui-ci.

12
SpoonMeiser

En supposant des entiers 32 bits:

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

Un peu plus concis:

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

Je ne suis pas vraiment sûr que je considérerais aussi "truc au niveau du bit" et "le plus simple". Je vois beaucoup de réponses qui supposent des entiers 32 bits signés (bien qu'il serait idiot de demander non signé); Je ne suis pas certain qu'ils s'appliqueraient aux valeurs à virgule flottante.

Il semble que la vérification "la plus simple" serait de comparer la façon dont les deux valeurs se comparent à 0; c'est assez générique en supposant que les types peuvent être comparés:

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

Si les signes sont opposés, vous vous trompez. Si les signes sont les mêmes, vous devenez vrai.

5
OwenP

(entier1 * entier2)> 0

Parce que lorsque deux entiers partagent un signe, le résultat de la multiplication sera toujours positif.

Vous pouvez également le faire> = 0 si vous voulez traiter 0 comme étant le même signe quoi qu'il arrive.

4
Benjamin Autin

En supposant que deux complètent l'arithmétique ( http://en.wikipedia.org/wiki/Two_complement ):

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

Cela peut prendre aussi peu que deux instructions et moins de 1 ns sur un processeur moderne avec optimisation.

Ne supposant pas que deux complètent l'arithmétique:

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

Cela peut nécessiter une ou deux instructions supplémentaires et prendre un peu plus de temps.

L'utilisation de la multiplication est une mauvaise idée car elle est vulnérable au débordement.

4
user10315

si (x * y)> 0 ...

en supposant non nul et autres.

3
Yes - that Jake.

En tant que note technique, les solutions bit-twiddly vont être beaucoup plus efficaces que la multiplication, même sur les architectures modernes. Ce n'est qu'environ 3 cycles que vous enregistrez, mais vous savez ce qu'ils disent à propos d'un "sou dépensé" ...

2
Daniel Spiewak

version C sans branche:

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

Modèle C++ pour les types entiers:

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

Juste au sommet de ma tête ...

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

Pour toute taille d'int avec l'arithmétique du complément à deux:

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

en supposant 32 bits

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

... la réponse if(x*y>0) est mauvaise en raison d'un débordement

1
ugasoft

si (a * b <0) le signe est différent, sinon le signe est le même (ou a ou b est zéro)

0
dogfish

En repensant à mes années universitaires, dans la plupart des représentations de machines, le bit le plus à gauche d'un entier est-il 1 lorsque le nombre est négatif et 0 lorsqu'il est positif?

J'imagine que cela dépend plutôt de la machine.

0
Dana

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

if (same_sign) ... else ...

0
andrew

Meilleure façon d'utiliser std :: signbit comme suit:

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

Il prend également en charge d'autres types de base (double, float, char etc.).

0
ashiquzzaman33