web-dev-qa-db-fra.com

Vérifier si un nombre est positif ou négatif à l'aide d'opérateurs au niveau du bit

Je peux vérifier si un nombre est impair/pair en utilisant des opérateurs au niveau du bit. Puis-je vérifier si un nombre est positif/zéro/négatif sans utiliser d'instructions/opérateurs conditionnels comme if/ternaire, etc.

Peut-on faire de même en utilisant des opérateurs au niveau du bit et une astuce en C ou en C++?

30
Anirudhh Er

Puis-je vérifier si un nombre est positif/zéro/négatif sans utiliser d'instructions/opérateurs conditionnels comme if/ternaire, etc.

Bien sûr:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
27
Konrad Rudolph

Si le bit haut est défini sur un entier signé (octet, long, etc., mais pas un nombre à virgule flottante), ce nombre est négatif.

int x = -2300;  // assuming a 32-bit int

if ((x & 0x80000000) != 0)
{
    // number is negative
}

AJOUTÉE:

Vous avez dit que vous ne vouliez utiliser aucun conditionnel. Je suppose que vous pourriez faire ceci:

int isNegative = (x & 0x80000000);

Et plus tard, vous pouvez le tester avec if (isNegative).

16
Jim Mischel

Il y a une discussion détaillée sur la page Bit Twiddling Hacks .

int v;      // we want to find the sign of v
int sign;   // the result goes here 

// CHAR_BIT is the number of bits per byte (normally 8).
sign = -(v < 0);  // if v < 0 then -1, else 0. 
// or, to avoid branching on CPUs with flag registers (IA32):
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1); 

// The last expression above evaluates to sign = v >> 31 for 32-bit integers.
// This is one operation faster than the obvious way, sign = -(v < 0). This
// trick works because when signed integers are shifted right, the value of the
// far left bit is copied to the other bits. The far left bit is 1 when the value
// is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior
// is architecture-specific.

// Alternatively, if you prefer the result be either -1 or +1, then use:

sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1));  // if v < 0 then -1, else +1

// On the other hand, if you prefer the result be either -1, 0, or +1, then use:

sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// Or, for more speed but less portability:
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1));  // -1, 0, or +1
// Or, for portability, brevity, and (perhaps) speed:
sign = (v > 0) - (v < 0); // -1, 0, or +1

// If instead you want to know if something is non-negative, resulting in +1
// or else 0, then use:

sign = 1 ^ ((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1

// Caveat: On March 7, 2003, Angus Duggan pointed out that the 1989 ANSI C
// specification leaves the result of signed right-shift implementation-defined,
// so on some systems this hack might not work. For greater portability, Toby
// Speight suggested on September 28, 2005 that CHAR_BIT be used here and
// throughout rather than assuming bytes were 8 bits long. Angus recommended
// the more portable versions above, involving casting on March 4, 2006.
// Rohit Garg suggested the version for non-negative integers on September 12, 2009. 
11
grokus

Ou, vous pouvez utiliser signbit() et le travail est fait pour vous.

Je suppose que sous le capot, le math.h l'implémentation est une vérification efficace au niveau du bit (pouvant éventuellement résoudre votre objectif initial).

Référence: http://en.cppreference.com/w/cpp/numeric/math/signbit

11
William Denniss
#include<stdio.h>

void main()
{
    int n;  // assuming int to be 32 bit long

    //shift it right 31 times so that MSB comes to LSB's position
    //and then and it with 0x1
    if ((n>>31) & 0x1 == 1) {
        printf("negative number\n");
    } else {
        printf("positive number\n");
    }

    getch();
}
4
Nitesh Pratap Singh

Les entiers signés et les virgules flottantes utilisent normalement le bit le plus significatif pour stocker le signe, donc si vous connaissez la taille, vous pouvez extraire les informations du bit le plus significatif.

Il y a généralement peu d'avantages à faire cela car une sorte de comparaison devra être faite pour utiliser ces informations et il est tout aussi facile pour un processeur de tester si quelque chose est négatif que de tester s'il n'est pas nul. Si c'est le cas sur les processeurs ARM, vérifier le bit le plus significatif sera normalement PLUS cher que de vérifier s'il est négatif à l'avance.

3
doron

C'est assez simple

Cela peut être fait facilement par

return ((!!x) | (x >> 31));

il revient

  • 1 pour un nombre positif,
  • -1 pour un négatif, et
  • 0 pour zéro
3
noufal
// if (x < 0) return -1
// else if (x == 0) return 0
// else return 1
int sign(int x) {
  // x_is_not_zero = 0 if x is 0 else x_is_not_zero = 1
  int x_is_not_zero = (( x | (~x + 1)) >> 31) & 0x1;
  return (x & 0x01 << 31) >> 31 | x_is_not_zero; // for minux x, don't care the last operand 
}

Voici exactement ce que vous vouliez!

2
Qylin

Voici une mise à jour liée à C++ 11 pour cette ancienne question. Il vaut également la peine d'envisager std :: signbit .

Sur l'Explorateur de compilateurs utilisant gcc 7.3 64 bits avec l'optimisation -O3, ce code

bool s1(double d)
{
    return d < 0.0;
}

génère

s1(double):
  pxor xmm1, xmm1
  ucomisd xmm1, xmm0
  seta al
  ret

Et ce code

bool s2(double d)
{
    return std::signbit(d);
}

génère

s2(double):
  movmskpd eax, xmm0
  and eax, 1
  ret

Vous auriez besoin d'un profil pour vous assurer qu'il y a une différence de vitesse, mais la version signbit utilise 1 opcode de moins.

2
Paul Floyd

Une façon plus simple de savoir si un nombre est positif ou négatif: laissez le nombre x vérifier si [x * (-1)]> x. si vrai x est négatif, sinon positif.

1
akundu
if( (num>>sizeof(int)*8 - 1) == 0 )
    // number is positive
else
   // number is negative

Si la valeur est 0, le nombre est positif, sinon négatif.

1
shashank

Cela ne peut pas être fait de manière portable avec des opérations sur les bits en C. Les représentations pour les types entiers signés que la norme autorise peuvent être beaucoup plus étranges que vous ne le pensez. En particulier, la valeur avec bit de signe activé et sinon zéro n'a pas besoin d'être une valeur autorisée pour le type signé ni le type non signé, mais une soi-disant représentation d'interruption pour les deux types.

Tous les calculs avec des opérateurs de bits que vous pouvez ainsi effectuer peuvent avoir un résultat qui conduit à un comportement indéfini.


En tout cas, comme le suggèrent certaines des autres réponses, ce n'est pas vraiment nécessaire et la comparaison avec < ou > devrait suffire dans n'importe quel contexte pratique, est plus efficace, plus facile à lire ... alors faites-le de cette façon.

1
Jens Gustedt

Vous pouvez faire la différence entre négatif/non négatif en regardant le bit le plus significatif. Dans toutes les représentations d'entiers signés, ce bit sera mis à 1 si le nombre est négatif.

Il n'y a pas de test pour faire la différence entre zéro et positif, à l'exception d'un test direct contre 0.

Pour tester le négatif, vous pouvez utiliser

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1)))
0

Supposons que votre numéro soit a=10 (positif). Si vous déplacez aa fois, cela donnera zéro.

c'est à dire:

10>>10 == 0

Vous pouvez donc vérifier si le nombre est positif, mais dans le cas où a=-10 (négatif):

-10>>-10 == -1

Vous pouvez donc les combiner dans un if:

if(!(a>>a))
   print number is positive
else 
   print no. is negative 
0
Sumesh rajput

Lorsque vous êtes sûr de la taille d'un entier (en supposant un entier 16 bits):

bool is_negative = (unsigned) signed_int_value >> 15;

Lorsque vous n'êtes pas sûr de la taille des entiers:

bool is_negative = (unsigned) signed_int_value >> (sizeof(int)*8)-1; //where 8 is bits

Le mot clé unsigned est facultatif.

0
Ino