Vérifier si un nombre est positif ou négatif en utilisant des opérateurs bitwise

je peux vérifier si un nombre est impair/même en utilisant des opérateurs bitwise. Puis-je vérifier si un nombre est positif/zéro/négatif sans utiliser de déclarations conditionnelles/opérateurs comme if/ternary etc.

peut-on faire la même chose en utilisant des opérateurs bitwise et un truc en c/" class="blnk">C ou en C++?

29
demandé sur Georg Fritzsche 2010-09-23 18:06:21

15 réponses

puis-je vérifier si un nombre est positif/zéro/négatif sans utiliser de déclarations conditionnelles/opérateurs comme if/ternary etc.

bien sûr:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
27
répondu Konrad Rudolph 2010-09-23 14:48:09

si le high bit est défini sur un entier signé (byte, long, etc., mais pas un nombre flottant), ce nombre est négatif.

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

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

ajouté:

vous avez dit que Vous ne voulez pas utiliser le conditionnel. Je suppose que tu peux faire ceci:

int isNegative = (x & 0x80000000);

Et au bout d'un certain temps, vous pouvez tester avec if (isNegative).

15
répondu Jim Mischel 2010-09-23 14:17:15

Il y a une discussion détaillée sur le Bit se Tourner les Hacks page.

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
répondu grokus 2010-09-23 17:00:56

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

je suppose que sous le capot, le math.h la mise en œuvre est une vérification bitwise efficace (peut-être la résolution de votre objectif original).

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

9
répondu William Denniss 2013-10-18 03:43:14
#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
répondu Nitesh Pratap Singh 2012-11-10 16:29:55

les entiers signés et les points flottants utilisent normalement le bit le plus significatif pour stocker le signe donc si vous connaissez la taille, vous pouvez extraire l'information 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 cette information et il est tout aussi facile pour un processeur de tester si quelque chose est négatif que de tester si ce n'est pas zéro. Si fait sur les processeurs de bras, vérifier le plus un bit significatif sera normalement plus coûteux que de vérifier s'il est négatif au départ.

3
répondu doron 2010-09-23 14:15:26

C'est assez simple

Il peut être fait facilement par

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

retourne

  • 1 pour un nombre positif,
  • -1 pour un négatif, et
  • 0 pour zéro
3
répondu noufal 2014-01-22 23:52:22
// 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 quel!

2
répondu Qylin 2013-04-23 11:17:25

cela ne peut pas être fait d'une manière portable avec des opérations de bits dans C. Les représentations pour les types entiers signés que la norme autorise peuvent être beaucoup plus bizarres que vous pourriez le soupçonner. En particulier, la valeur avec signe bit on et autrement zéro ne doit pas nécessairement être une valeur admissible pour le type signé ni pour le type non signé, mais une représentation dite piège pour les deux types.

tous les calculs avec des opérateurs de bits que vous pouvez donc faire pourraient avoir un résultat qui conduit à des comportement.


dans tous les cas comme le suggèrent certaines autres réponses, ce n'est pas vraiment nécessaire et la comparaison avec < ou > devrait suffire dans tout contexte pratique, plus efficace, plus facile à lire... si juste de le faire de cette façon.

1
répondu Jens Gustedt 2010-09-23 15:16:18
if( (num>>sizeof(int)*8 - 1) == 0 )
    // number is positive
else
   // number is negative

si la valeur est 0 alors le nombre est positif sinon négatif

1
répondu shashank 2014-08-01 05:52:19

Un moyen simple de savoir si un nombre est positif ou négatif: Que le nombre soit x vérifier si [x * (-1)] > X. si le vrai x est négatif, il est positif.

1
répondu akundu 2015-11-07 21:30:30

Vous pouvez différencier les négatifs/non négatif en regardant le bit le plus significatif. Dans toutes les représentations pour les entiers signés, ce bit sera fixé à 1 si le nombre est négatif.

il n'y a pas de test pour distinguer le zéro du positif, sauf pour un test direct contre 0.

À tester pour le négatif, vous pouvez utiliser

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1)))
0
répondu Bart van Ingen Schenau 2010-09-23 14:20:58

supposons que votre numéro soit a=10 (positif). Si vous maj aa fois, il donnera à zéro.

j'.e:

10>>10 == 0

ainsi vous pouvez vérifier si le nombre est positif, mais dans le cas 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
répondu Sumesh rajput 2011-11-20 14:50:38

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

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

unsigned mot clé est facultatif.

0
répondu Ino 2013-10-30 23:46:36

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

sur L'Explorateur de compilateur utilisant gcc 7.3 64bit avec l'optimisation-O3, ce code

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

produit

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

et ce code

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

produit

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

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

0
répondu Paul Floyd 2018-03-08 16:53:48