Est-il possible de différencier entre 0 et -0?

Je sais que les valeurs entières 0 et -0 sont essentiellement les mêmes. Mais je me demande s’il est possible de les différencier.

Par exemple, comment savoir si une variable a été affectée à -0 ?

 bool IsNegative(int num) { // How ? } int num = -0; int additinon = 5; num += (IsNegative(num)) ? -addition : addition; 

La valeur -0 enregistrée dans la mémoire exactement comme 0 ?

Cela dépend de la machine que vous ciblez.

Sur une machine qui utilise une représentation en complément à 2 pour les entiers, il n’y a pas de différence au niveau du bit entre 0 et -0 (ils ont la même représentation)

Si votre machine utilisait son complément , vous pourriez certainement

 0000 0000 -> signed 0 1111 1111 -> signed −0 

Évidemment, nous parlons d’utiliser un support natif , les processeurs de la série x86 ont un support natif pour la représentation des nombres signés en complément à deux. L’utilisation d’autres représentations est certainement possible mais serait probablement moins efficace et nécessiterait plus d’instructions.

(Comme JerryCoffin l’a également noté: même si le complément a été considéré principalement pour des raisons historiques, les représentations en magnitude signée sont encore assez courantes et ont une représentation séparée pour le zéro négatif et positif)

Pour un int (dans la représentation quasi universelle du “complément à 2”), les représentations de 0 et -0 sont les mêmes. (Ils peuvent être différents pour d’autres représentations numériques, par exemple, virgule flottante IEEE 754).

Commençons par représenter le complément 0 dans 2 (bien sûr, il existe de nombreux autres systèmes et représentations, ici je fais référence à celui-ci), en supposant que 8 bits, zéro est:

 0000 0000 

Maintenant, retournons tous les bits et ajoutons 1 pour obtenir le complément à 2:

 1111 1111 (flip) 0000 0001 (add one) --------- 0000 0000 

nous avons 0000 0000 , et c’est aussi la représentation de -0.

Mais notez que dans le complément à 1, le 0 signé est 0000 0000, mais -0 est 1111 1111.

J’ai décidé de laisser cette réponse car les implémentations C et C ++ sont généralement étroitement liées, mais en fait, elles ne respectent pas le standard C comme je le pensais. Le point rest que le standard C ++ ne spécifie pas ce qui se passe pour des cas comme ceux-ci. Il est également intéressant de noter que les représentations sans complément à deux sont extrêmement rares dans le monde réel et que, même lorsqu’elles existent, elles cachent souvent la différence dans de nombreux cas plutôt que de l’exposer à quelque chose que quelqu’un pourrait facilement découvrir.


Le comportement des zéros négatifs dans les représentations entières dans lesquelles ils existent est moins rigoureusement défini dans le standard C ++ que dans le standard C. Il cite toutefois la norme C (ISO / IEC 9899: 1999) en tant que référence normative au niveau supérieur [1.2].

Dans le standard C [6.2.6.2], un zéro négatif ne peut être que le résultat d’opérations binarys ou d’opérations où un zéro négatif est déjà présent (par exemple, multiplier ou diviser un zéro négatif par une valeur ou append un zéro négatif à zéro) – l’application de l’opérateur unaire moins à une valeur d’un zéro normal, comme dans votre exemple, est donc garantie pour un zéro normal.

Même dans les cas qui peuvent générer un zéro négatif, rien ne garantit qu’ils le feront, même sur un système prenant en charge le zéro négatif:

Il n’est pas spécifié si ces cas génèrent réellement un zéro négatif ou un zéro normal, et si un zéro négatif devient un zéro normal lorsqu’il est stocké dans un object.

Par conséquent, nous pouvons conclure: non, il n’y a pas de moyen fiable pour détecter ce cas. Même si ce n’est pas parce que les représentations non complémentaires sont très rares dans les systèmes informatiques modernes.

La norme C ++, pour sa part, ne mentionne pas le terme “zéro négatif” et a très peu de discussion sur les détails de l’ampleur signée et des représentations du complément, sauf pour noter [3.9.1 para 7] qu’ils sont autorisés.

Si votre machine a des représentations distinctes pour -0 et +0 , alors memcmp pourra les distinguer.

Si des bits de remplissage sont présents, il peut y avoir plusieurs représentations pour des valeurs autres que zéro.

Dans la spécification du langage C ++, il n’y a pas d’int tel que le zéro négatif .

La seule signification de ces deux mots est l’opérateur unaire - appliqué à 0 , tout comme trois plus cinq ne sont que l’opérateur binary + appliqué à 3 et 5 .

S’il y avait un zéro négatif distinct, le complément de deux (la représentation la plus courante des types entiers) serait une représentation insuffisante pour les implémentations C ++, car il n’y a aucun moyen de représenter deux formes de zéro.


En revanche, les points flottants (après IEEE) ont des zéros positifs et négatifs séparés. On peut les distinguer, par exemple, en les divisant par 1. Le zéro positif produit un infini positif; le zéro négatif produit l’infini négatif.


Cependant, s’il existe différentes représentations mémoire de l’int 0 (ou de tout int, ou de toute autre valeur d’un autre type), vous pouvez utiliser memcmp pour découvrir que:

 #include  int main() { int a = ... int b = ... if (memcmp(&a, &b, sizeof(int))) { // a and b have different representations in memory } } 

Bien sûr, si cela se produisait, en dehors des opérations de mémoire directe, les deux valeurs fonctionneraient exactement de la même manière.

Pour simplifier, j’ai trouvé plus facile de visualiser.

Le type int (_32) est stocké avec 32 bits . 32 bits signifie 2 ^ 32 = 4294967296 valeurs uniques . Ainsi :

la plage de données unsigned int est comprise entre 0 et 4 294 967 295

En cas de valeurs négatives, cela dépend de la manière dont elles sont stockées. Au cas où

  • Complément de deux –2 147 483 648 à 2 147 483 647
  • Complément de prix: -2 147 483 647 à 2 147 483 647

Dans le cas où la valeur du complément de -0 existe.