2010-09-16 12 views
5

En utilisant des opérateurs au niveau du bit et je suppose que l'addition et la soustraction, comment puis-je vérifier si un entier signé est positif (spécifiquement, non négatif et non nul)? Je suis sûr que la réponse à cette question est très simple, mais elle ne vient tout simplement pas à moi.Comment puis-je vérifier si un entier signé est positif?

+2

Juste une pensée - les réponses ci-dessous sont bonnes, mais je pense que vous ne devriez pas les utiliser dans la pratique parce que sur un CPU moderne, une comparaison comme "> 0" est juste 1 instruction, et l'une des réponses ci-dessous vont être des instructions multiples, éventuellement ne pas utiliser des pipelines séparés ou des noyaux. Ils sont utiles si vous faites votre propre circuit pour une comparaison spéciale et que vous devez réduire le délai du chemin logique. – Phil

+0

Cela pourrait être une question de devoirs limitant spécifiquement l'utilisation de ces comparaisons :) – Alex

+0

il est lié à un plus grand problème de devoirs, c'est juste une partie que je ne peux pas saisir – Rowhawn

Répondre

4

Si vous voulez vraiment un « est strictement positif » prédicat pour int n sans utiliser conditionals (en supposant complément à 2):

  • -n aura le signe (en haut) bit set si n était strictement positif et clair dans tous les autres cas à l'exception den == INT_MIN;
  • ~n aura le bit de signe défini si n était strictement positif, ou 0, et clair dans tous les autres cas, y compris n == INT_MIN;
  • ... donc -n & ~n aura le bit de signe fixé si n était strictement positif, et effacer dans tous les autres cas.

Appliquer un non signé changement pour en faire un 0/1 réponse:

int strictly_positive = (unsigned)(-n & ~n) >> ((sizeof(int) * CHAR_BIT) - 1); 

EDIT: comme points cafs dans les commentaires, -n provoque un débordement lorsque n == INT_MIN (en supposant toujours le complément de 2). La norme C permet au programme d'échouer dans ce cas (par exemple, vous pouvez activer les interruptions pour le débordement signé en utilisant GCC avec l'option -ftrapv). Casting n à unsigned résout le problème (l'arithmétique non signée ne provoque pas de débordements). Donc une amélioration serait:

unsigned u = (unsigned)n; 
int strictly_positive = (-u & ~u) >> ((sizeof(int) * CHAR_BIT) - 1); 
+0

merci, cela m'a vraiment aidé à obtenir ce que je voulais – Rowhawn

+0

'-n' peut déborder dans le cas de' n == INT_MIN'. – caf

+0

Strictement, cela ne fonctionne que sur l'arithmétique du complément à 2 (qui sont, je vous l'accorde, les systèmes pratiquement significatifs). Avec un zéro négatif (complément de 1 ou grandeur de signe), vos affirmations ne sont pas valides. –

3

Vérifiez le bit le plus significatif. 0 est positif, 1 est négatif.

+1

Ceci échoue pour zéro, ce qui n'est ni positif ni négatif. – caf

+0

Mais si le bit le plus significatif est 0 et que tous les autres bits sont à zéro, il renvoie 'positif' mais zéro est supposé être exclu. –

+0

Vous avez raison, bien qu'il puisse vérifier someInt == 0; – Alex

1

Considérez comment la signature est représentée. Souvent, il est fait avec deux-complément ou avec un simple bit signe - Je pense que ces deux pourraient être vérifiés avec un simple et logique.

0

Vérifiez que n'est pas 0 et le bit le plus significatif est 0, quelque chose comme:

int positive(int x) { 
    return x && (x & 0x80000000); 
} 
+0

En supposant sizeof (int) == 4 ... –

+0

Qu'en est-il du retour x && (x & MIN_INT)? – Ssancho

3

Si vous ne pouvez pas utiliser les opérateurs de comparaison évidentes, alors vous devez travailler plus dur:

int i = anyValue; 
if (i && !(i & (1U << (sizeof(int) * CHAR_BIT - 1)))) 
    /* I'm almost positive it is positive */ 

Le premier terme vérifie que la valeur n'est pas nulle; la seconde vérifie que la valeur n'a pas le bit de début défini. Cela devrait fonctionner pour les entiers en complément de 2, en complément de 1 ou en nombre de signes.

+0

Malheureusement, il a un comportement indéfini;) - 2 élevé à la puissance de '(sizeof (int) * CHAR_BIT - 1)' n'est certainement pas représentable dans 'int'. – caf

+0

@caf: qui peut être adressée en convertissant le 1 qui est décalé à 'unsigned int' avec un suffixe U ... ce qui signifie que' i' sera aussi converti en 'unsigned int'. Le décalage de bits devrait normalement être effectué sur des quantités non signées de toute façon. –

+0

Oui, cela corrige l'UB - maintenant vous avez juste à vous soucier du cas (encore plus théorique!) Où 'int' et' unsigned int' ont le même nombre de bits de valeur ... – caf

Questions connexes