Pourquoi le signe est-il différent après soustraction non signé et signé?

unsigned int t = 10;
int d = 16;
float c = t - d;
int e = t - d;

Pourquoi la valeur de c positif, mais e négatif?

34
demandé sur Rishav 2018-10-11 10:23:26

2 réponses

commençons par analyser le résultat de t - d.

t est un unsigned intd est un int, donc pour faire de l'arithmétique sur eux, la valeur de d est converti en unsigned int (les règles de c++ disent que non signé obtient la préférence ici). Nous obtenons donc 10u - 16u, ce qui (en supposant que 32 bits int) s'enroule autour de 4294967290u.

Cette valeur est ensuite convertie float dans la première déclaration, et à int dans le second.

en supposant que typique de la mise en œuvre de float (32 bits simple précision IEEE), sa plus grande valeur représentable est à peu près 1e38, donc 4294967290u est bien à l'intérieur de cette fourchette. Il y aura des erreurs d'arrondi, mais la conversion float ne débordera pas.

int, la situation est différente. 4294967290u est trop grand pour tenir dans un int, donc l'enroulement se produit et nous arrivons à la valeur -6. Il est à noter que cette enroulement n'est pas garanti par la norme: la valeur résultante dans cette cas de la mise en œuvre est définie par (1), ce qui signifie que c'est au compilateur que la valeur du résultat est, mais il doit être documenté.


(1) C++17 (N4659), [conv.intégrale] 7.8/3:

Si le type de destination est signé, la valeur est inchangée si elle peut être représentée dans le type de destination; autrement, la valeur est définie par la mise en œuvre.

57
répondu Angew 2018-10-11 16:47:30

tout d'Abord, vous devez comprendre "d'habitude arithmétique des conversions" (ce lien est pour C, mais les règles sont les mêmes en C++). En C++, si vous faites de l'arithmétique avec des types mixtes (vous devriez éviter cela si possible, soit dit en passant), il y a un ensemble de règles qui décide dans quel type le calcul est fait.

dans votre cas, vous soustrayez un int signé d'un int non signé. Les règles de promotion disent que le calcul réel est fait en utilisant unsigned int.

Donc votre calcul est 10 - 16 en arithmétique int non signée. L'arithmétique non signée est l'arithmétique modulo, ce qui signifie qu'il enroule autour. Ainsi, en supposant votre int 32-bit typique, le résultat de ce calcul est 2^32 - 6.

C'est la même pour les deux lignes. Notez que la soustraction est complètement indépendante de la tâche; le type sur le côté gauche n'a absolument aucune influence sur la façon dont le calcul se produit. C'est un débutant erreur de penser que le type sur le côté gauche d'une façon ou d'une autre influence le calcul; mais float f = 5 / 6 est zéro, parce que la division utilise toujours l'arithmétique entière.

la différence, alors, c'est ce qui se passe pendant la mission. Le résultat de la soustraction est implicitement converti en float et int dans l'autre.

La conversion de flotter essaie de trouver la valeur la plus proche du réel que le type peut représenter. Ce sera une valeur très grande; pas tout à fait celle de la soustraction d'origine donné de si.

la conversion en int indique que si la valeur entre dans la gamme de int, la valeur sera inchangée. Mais 2^32-6 est beaucoup plus grand que le 2^31 - 1 qu'un int de 32 bits peut contenir, donc vous obtenez l'autre partie de la règle de conversion, qui dit que la valeur résultante est implémentation-défini. Il s'agit d'un terme de la norme qui signifie "différents compilateurs peuvent faire différentes choses, mais ils doivent documenter ce qu'ils font".

à toutes fins pratiques, tous les compilateurs que vous rencontrerez probablement disent que le modèle de bits reste le même et est juste interprété comme signé. En raison de la façon dont l'arithmétique du complément de 2 fonctionne (la façon dont presque tous les ordinateurs représentent des nombres négatifs), le résultat est le -6 vous attendriez du calcul.

mais tout cela est une très longue façon de répéter le premier point, qui est "ne pas faire l'arithmétique de type mixte". Lancer les types en premier, explicitement, aux types que vous savez faire le droit chose.

14
répondu Sebastian Redl 2018-10-11 13:10:32