Comment se fait-il que dans l'extrait suivant
int a = 7;
int b = 3;
double c = 0;
c = a / b;
c
finit par avoir la valeur 2 plutôt que 2,33333, comme on pourrait s'y attendre. Si a
et b
sont des doubles, la réponse passe à 2.333. Mais sûrement parce que c
est déjà un double, il aurait dû fonctionner avec des entiers?
Alors, comment ça se fait int/int=double
ne fonctionne pas?
En effet, vous utilisez la version à division entière de operator/
, qui prend 2 int
s et retourne un int
. Pour utiliser la version double
, qui retourne un double
, au moins un des int
s doit être explicitement converti en double
.
c = a/(double)b;
C'est ici:
a) La division de deux int
s effectue toujours une division entière. Donc, le résultat de a/b
Dans votre cas ne peut être qu'un int
.
Si vous voulez conserver a
et b
en tant que int
s, tout en les divisant complètement, vous devez en convertir au moins un pour doubler: (double)a/b
Ou a/(double)b
ou (double)a/(double)b
.
b) c
est un double
, donc il peut accepter une valeur int
lors de l'attribution: le int
est automatiquement converti en double
et attribué à c
.
c) Rappelez-vous que lors de l'affectation, l'expression à droite de =
est calculée première (selon la règle (a) ci-dessus, et sans égard à la variable à gauche de =
) Et alors assigné à la variable à gauche de =
(Selon (b) ci-dessus). Je crois que cela complète le tableau.
À de très rares exceptions près (je ne peux en penser qu’un seul), C++ détermine le sens entier d’une expression (ou sous-expression) à partir de l’expression elle-même. Ce que vous faites avec les résultats de l'expression n'a pas d'importance. Dans votre cas, dans l'expression a / b
, il n'y a pas de double
en vue; tout est int
. Donc, le compilateur utilise la division entière. Une fois le résultat obtenu, il considère ce qu'il doit en faire et le convertit en double
.
Lorsque vous divisez deux entiers, le résultat sera un entier, indépendamment du fait que vous le stockiez dans un double.
c
est une variable double
, mais la valeur qui lui est affectée est une valeur int
car elle résulte de la division de deux int
s, ce qui vous donne "division entière" (en laissant tomber le reste). Alors qu'est-ce qui se passe dans la ligne c=a/b
est
a/b
est évalué, créant un temporaire de type int
c
après la conversion en type double
.La valeur de a/b
est déterminé sans référence à son contexte (affectation à double
).
En langage C++, le résultat de la sous-expression n'est jamais affecté par le contexte (sauf quelques rares exceptions). C'est l'un des principes que le langage suit avec soin. L'expression c = a / b
contient une sous-expression indépendante a / b
, qui est interprété indépendamment de tout ce qui est en dehors de cette sous-expression. Peu importe la langue, vous assignerez ensuite le résultat à un double
. a / b
est une division entière. Tout le reste n'a pas d'importance. Vous verrez ce principe suivre dans de nombreux coins de la spécification de langue. Voilà comment fonctionne le C++ (et le C).
Un exemple d'exception que j'ai mentionné ci-dessus est l'affectation/l'initialisation d'un pointeur de fonction dans des situations de surcharge de fonction.
void foo(int);
void foo(double);
void (*p)(double) = &foo; // automatically selects `foo(fouble)`
Il s'agit d'un contexte où le côté gauche d'une affectation/initialisation affecte le comportement du côté droit. (En outre, l'initialisation de la référence à la matrice empêche la dégradation du type de matrice, ce qui est un autre exemple de comportement similaire.) Dans tous les autres cas, le côté droit ignore complètement le côté gauche.
L'opérateur /
Peut être utilisé pour la division entière ou la division en virgule flottante. Vous lui donnez deux opérandes entiers, donc on fait une division entière et ensuite le résultat est stocké dans un double.
Techniquement, cela dépend des langues, mais presque toutes les langues traitent ce sujet de la même manière. Lorsqu'il y a une incompatibilité de type entre deux types de données dans une expression, la plupart des langues tentent de transtyper les données d'un côté du =
Pour faire correspondre les données de l'autre côté en fonction d'un ensemble de règles prédéfinies.
Lorsque vous divisez deux nombres du même type (entiers, doubles, etc.), le résultat sera toujours du même type (donc 'int/int' donnera toujours int).
Dans ce cas, vous avez double var = integer result
Qui convertit le résultat entier en un double après le calcul , auquel cas les données fractionnaires sont déjà perdues. (la plupart des langues font cette conversion pour éviter les inexactitudes de type sans déclencher une exception ou une erreur).
Si vous souhaitez conserver le résultat en double, vous allez créer une situation dans laquelle vous avez double var = double result
La façon la plus simple de le faire est de forcer l'expression du côté droit d'une équation à doubler:
c = a/(double)b
La division entre un entier et un double aura pour résultat de transformer l'entier en double (notez qu'en calculant, le compilateur passe souvent au "upcast" du type de données le plus spécifique pour éviter la perte de données).
Après le upcast, a
se terminera par un double et vous avez maintenant une division entre deux doubles. Cela créera la division et l’affectation souhaitées.
AGAIN, Veuillez noter que ceci est spécifique à la langue (et peut même être spécifique au compilateur), cependant, presque toutes les langues (certainement toutes celles auxquelles je peux penser par cœur) traitent cet exemple de la même manière.