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

94

Je sais que les valeurs entières 0et -0sont 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 est-elle -0enregistrée dans la mémoire exactement de la même manière que 0?

Filip Minx
la source
9
Pour les entiers, il n'y a pas de différence.
Maroun
14
Cela dépend de l'implémentation, mais pour les implémentations où intest représenté dans le complément de 2 (de loin le plus couramment rencontré), 0et -0ont des représentations bit à bit identiques.
Mankarse
11
Sur une machine à complément 2, il n'y a pas de différence au niveau du bit.
Marco A.
17
@VirtualSnake: Que signifie "en binaire"? Il existe en effet des encodages binaires pour lesquels il existe une distinction entre -0 et 0. Signe et magnitude, par exemple.
Benjamin Lindley
8
@VirtualSnake C'est vrai, nous parlons int. Voir l'encodage du complément de Ones .
CiaPan

Réponses:

112

Cela dépend de la machine que vous ciblez.

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

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

0000 0000   -> signed01111 1111   -> signed   0

De toute évidence, nous parlons de l'utilisation du support natif , les processeurs de la série x86 ont un support natif pour la représentation complémentaire à deux des nombres signés. 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 son complément a été considéré principalement pour des raisons historiques, les représentations de magnitude signées sont encore assez courantes et ont une représentation séparée pour le zéro négatif et positif)

Marco A.
la source
6
@TobiMcNamobi: Pas assez pour s'inquiéter. Je serais surpris si quelqu'un a déjà pris la peine de porter un compilateur C ++ pour produire une sortie pour une telle machine.
Benjamin Lindley
1
Je suis d'accord avec Benjamin, historiquement il y a eu des machines qui l'utilisent, mais aujourd'hui je ne connais pas de machines de production qui l'utilisent. Néanmoins, il est toujours bon de savoir et de garder à l'esprit.
Marco A.
4
Le complément @TobiMcNamobi est toujours utilisé dans le système UNISYS 2200 stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv
2
Je n'ai jamais examiné les exigences du complément à un - la norme garantit-elle réellement cela 0et -0est-elle différente ? Honnêtement, je me serais attendu à ce qu'il se comporte plus comme autorisant des représentations à deux bits de la même valeur, et votre programme peut utiliser celui qui lui convient.
8
@Hurkly: non, même si une représentation zéro négatif existe, le standard ne garantit pas que l'affectation ou l'initialisation à l'aide de l'expression -0, c'est-à-dire le résultat de l'application de l' -opérateur unaire à la constante entière 0, soit une représentation zéro négative. Indépendamment de la représentation, la norme ne dit jamais 0et il -0y a des valeurs mathématiquement différentes, seulement qu'il pourrait y avoir un modèle de bit négatif à zéro. Si tel est le cas, il représente toujours la même valeur numérique, 0.
Steve Jessop
14

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

RichieHindle
la source
9
>> En supposant une représentation du complément à 2
Marco A.
12

Commençons par représenter 0 dans le complément de 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 des 2:

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

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

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

Maroun
la source
1
Puis-je savoir pourquoi les votes négatifs afin d'améliorer ma réponse s'il vous plaît?
Maroun
1
Alors que la plupart des autres réponses sont techniquement correctes, votre réponse est pratique et fournit une implémentation. Bien.
umlcat
9

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, cela ne se réfère pas au standard C comme je le pensais. Le fait est que la norme C ++ ne spécifie pas ce qui se passe pour de tels cas. Il est également pertinent que les représentations non complémentaires à deux soient extrêmement rares dans le monde réel et que même là où elles existent, elles cachent souvent la différence dans de nombreux cas plutôt que de l'exposer comme quelque chose que quelqu'un pourrait facilement s'attendre à découvrir.


Le comportement des zéros négatifs dans les représentations entières dans lesquelles ils existent n'est pas aussi rigoureusement défini dans le standard C ++ que dans le standard C. Il cite cependant la norme C (ISO / CEI 9899: 1999) comme référence normative au plus haut niveau [1.2].

Dans la norme C [6.2.6.2], un zéro négatif ne peut être que le résultat d'opérations au niveau du bit, 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 ajouter 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 aboutir à un zéro normal.

Même dans les cas qui peuvent générer un zéro négatif, il n'y a aucune garantie qu'ils le feront, même sur un système qui prend en charge le zéro négatif:

Il n'est pas précisé 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 objet.

Par conséquent, nous pouvons conclure: non, il n'existe aucun moyen fiable de détecter ce cas. Même si ce n'est pas pour le fait que les représentations à complément non double sont très rares dans les systèmes informatiques modernes.

Le standard C ++, pour sa part, ne fait aucune mention du terme «zéro négatif», et a très peu de discussion sur les détails de la grandeur signée et des représentations complémentaires de chacun, sauf pour noter [3.9.1 para 7] qu'ils sont autorisés.

Aléatoire832
la source
En général non, le fait que quelque chose soit vrai / requis en C ne signifie pas nécessairement que c'est vrai / requis en C ++. Le fait que C soit une référence normative signifie que C ++ fait référence au standard C pour diverses choses (principalement le contenu des en-têtes standard), mais la définition des types entiers ne fait pas partie de ces choses. Cependant, l'absence d'un moyen garanti de produire un zéro négatif signifie que ce que vous concluez est toujours vrai, il n'y a pas de moyen sûr d'en générer un en utilisant l'arithmétique même si la représentation existe.
Steve Jessop
Alors pourquoi la norme C ++ entre-elle tellement moins en détail sur des choses comme celle-ci?
Random832
1
Goût personnel, je pense, si le nombre de personnes votant sur le standard C ++ peut être considéré comme "personnel" :-) Si cela devait se reporter au standard C pour les définitions, alors il pourrait faire un bon travail. et ne contiennent aucun détail, comme dans certains autres cas.
Steve Jessop
Est-ce que "C ++ est un langage de programmation à usage général basé sur le langage de programmation C tel que décrit dans ISO / CEI 9899: 1999 Langages de programmation - C (ci-après dénommé le standard C)." [1.1 para 2] a un sens normatif? Je pensais que cela visait à incorporer généralement le standard C pour tout ce qui n'est pas spécifiquement remplacé par le standard C ++.
Random832
@ Random832 Non , il de juste une note historique (il y a, par exemple, pas _Boolou _Complexou initialiseurs ou littéraux composés désignés en C ++). Le standard C ++ sait comment incorporer le standard C quand il le souhaite - par exemple, [basic.fundamental] / p3: "Les types entiers signés et non signés doivent satisfaire les contraintes données dans le standard C, section 5.2.4.2.1."
TC
8

Si votre machine a des représentations distinctes pour -0et +0, alors memcmpsera en mesure de les distinguer.

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

Ben Voigt
la source
5

Dans la spécification du langage C ++, il n'existe aucun int comme zéro négatif .

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

S'il y avait un zéro négatif distinct , le complément à 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 virgules flottantes (suivant IEEE) ont des zéros positifs et négatifs séparés. Ils peuvent être distingués, par exemple, en divisant 1 par eux. Le zéro positif produit l'infini positif; zéro négatif produit l'infini négatif.


Cependant, s'il se trouve qu'il existe différentes représentations mémoire de l'int 0 (ou de tout int, ou de toute autre valeur de tout autre type), vous pouvez utiliser memcmppour découvrir que:

#include <string>

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 toujours exactement de la même manière.

Paul Draper
la source
3
En fait, le langage qui n'impose pas son existence ne signifie pas qu'il impose son absence. Indice: il ne rend obligatoire ni l'un ni l'autre.
Deduplicator
2
@Deduplicator, en quelque sorte. Par «dans le langage C ++», je veux dire «dans la spécification du langage C ++ ». Puisqu'il n'y a pas non plus de mention des froobinateurs dans la spécification, je pourrais dire "C ++ n'a pas de froobinateurs" sans trop d'ambiguïté. Je pensais que c'était clair, mais je vais l'améliorer.
Paul Draper
1
La spécification de la langue ne mentionne pas non plus les licornes.
ypercubeᵀᴹ
2

Pour simplifier, je l'ai trouvé plus facile à visualiser.

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

La plage de données int non signée va de 0 à 4 294 967 295

En cas de valeurs négatives, cela dépend de la façon dont elles sont stockées. Au cas où

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

En cas de complément de One, la valeur -0 existe.

Margus
la source
2
Je n'ai pas voté contre mais les plates-formes pour lesquelles intn'est pas stocké en 32 bits sont plus populaires que les plates-formes avec son complément de nos jours.
Maciej Piechotka