Question

Quel est le moyen le plus simple de vérifier si deux entiers ont le même signe? Y at-il une astuce au bit près pour faire cela?

Était-ce utile?

La solution

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

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

Bien sûr, vous pouvez créer un gabarit et créer un modèle:

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

Remarque: comme nous utilisons exclusif ou, nous voulons que le LHS et le RHS soient différents lorsque les signes sont identiques, ainsi la vérification par rapport à zéro est différente.

Autres conseils

Quel est le problème avec

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

?

(a ^ b) >= 0

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

Je me méfierais de toute astuce au niveau des bits 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 forme de complément à deux , mais ce n'est pas le cas. Il est recommandé de faire des suppositions sur les composants internes d’un système, sauf si vous utilisez un type de données garantissant un format de stockage particulier.

En complément 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 de pouvoir 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 mise en œuvre dans la plupart des langues.

Personnellement, je n’utiliserais que la fonction de signe de la langue de votre choix. Il est peu probable qu’un tel calcul pose des problèmes de performances.

En supposant que les bits 32 bits:

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

Légèrement plus concis:

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

Je ne suis pas vraiment sûr que je considérerais & "; astuce au niveau du bit &"; et " le plus simple " être synonyme. Je vois beaucoup de réponses qui supposent des entiers signés sur 32 bits (bien que ce soit , il serait ridicule de demander non signé); Je ne suis pas sûr qu'ils s'appliqueraient aux valeurs en virgule flottante.

Il semble que le " plus simple " vérifier serait de comparer comment 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 obtenez faux. Si les signes sont les mêmes, vous devenez vrai.

(entier1 * entier2) > 0

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

Vous pouvez également le définir > = 0 si vous souhaitez que 0 soit considéré comme le même signe, quoi qu'il en soit.

if (x * y) > 0 ...

en supposant que non nul et tel.

En guise de remarque technique, les solutions simples vont beaucoup plus efficacement que la multiplication, même sur les architectures modernes. Vous ne sauvegardez que 3 cycles environ, mais vous savez ce qu’ils disent d’un & "Penny save &"; ...

Juste du haut de ma tête ...

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

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

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

en supposant que 32 bits

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

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

si le signe (a * b < 0) est différent, sinon le signe est identique (ou a ou b vaut zéro)

Si je repense à mes années d’université, dans la plupart des représentations d’ordinateur, le bit le plus à gauche d’un entier n’est-il pas un 1 lorsque le nombre est négatif et 0 lorsqu'il est positif?

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

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

if (same_sign) ... sinon ...

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.).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top