Résumé
Cette leçon ouvre la troisième unité du cours, consacrée aux expressions et à leurs opérateurs. Elle explique à quoi sert l’unité : enseigner à construire des expressions dont la valeur se prédit avec certitude, en sachant quelle opération est effectuée d’abord, de quel type est le résultat, quels effets de bord elles ont et quelles expressions n’ont pas de signification ; elle présente ses quatre leçons et le fil qui les relie, de l’arithmétique entière et réelle jusqu’aux bits et à la bibliothèque mathématique, en passant par les conditions et par le catalogue du comportement indéfini ; elle rappelle ce que l’unité tient pour acquis de la deuxième, à savoir le type de chaque donnée, ses limites et ses conversions ; elle formule le problème que l’unité résout, celui d’un programme qui compile sans un seul avertissement et dont les réponses à six questions scolaires sont toutes fausses, quand elles ne manquent pas ; et elle montre où elle mène, dans les unités suivantes et dans le cours Programmation en C++ II.
Objectifs d’apprentissage
- Décrire la suite des contenus de l’unité et expliquer ce que chaque leçon apporte à la suivante.
- Se rappeler le nécessaire de l’unité 2 (les types entiers et réels, leurs plages, le dépassement et les conversions) et le revoir si besoin.
- Anticiper, sur un exemple, que la valeur d’une expression dépend de règles d’évaluation (la priorité, le type des opérandes, l’ordre des effets) qui ne coïncident pas toujours avec celles des mathématiques scolaires.
- Reconnaître ce que l’on attend de savoir faire à la fin de l’unité, et le distinguer de ce que l’on apprendra dans les unités suivantes.
Évaluation d’entrée
Avant de parcourir l’unité, il convient de mesurer le point de départ. Cette évaluation est une autoévaluation : elle n’est pas notée, et son seul but est d’orienter l’étude. Les quatre premières questions vérifient ce que l’unité tient pour acquis de la deuxième : la division entre entiers, l’écriture en base 2, la soustraction non signée et le dépassement signé. Les six suivantes touchent, dans l’ordre des leçons, aux idées centrales de l’unité, et plusieurs d’entre elles partent des mathématiques scolaires ou de la logique élémentaire. Personne n’est tenu de les réussir déjà, et pour deux d’entre elles « je ne le sais pas encore » est une réponse honnête : chaque réponse, juste ou non, explique le point et nomme la leçon qui le traite. Les mêmes compétences sont mesurées de nouveau à la fin, dans la leçon de synthèse.
Avant de commencer l’unité, mesurez votre point de départ. C’est une autoévaluation brève : elle n’est pas notée et son résultat n’est conservé que dans votre navigateur.
Question 1Des unités précédentesUn programme déclare
const double r{7 / 2};et écritr. Qu’apparaît-il ?Croit que le type de la variable décide de la manière de diviser ; c’est le type des opérandes qui en décide.Croit que la division entière arrondit ; elle supprime la partie décimale.La valeur 3 est constante et se représente exactement dans undouble: il n’y a pas de rétrécissement à rejeter.La division7 / 2a lieu entre entiers et donne le quotient entier, 3 ; c’est seulement ensuite que ce 3 est converti endouble. C’est le type des opérandes qui décide de l’opération, non le type de la variable qui reçoit le résultat. La leçon 3.1 transforme cette observation en une règle générale : le type se décide en chaque nœud de l’expression.Question 2Des unités précédentesComment s’écrit le nombre 13 en base 2, sur huit bits ?
Additionne mal les poids : .Écrit les restes des divisions successives dans l’ordre où ils sortent ; on les lit du dernier au premier.Ce motif vaut 26, le double de 13 : les bits sont décalés d’une position.Chaque position pèse le double de celle qui est à sa droite : les uns occupent les positions de poids 8, 4 et 1. La leçon 3.4 opère directement sur ces bits, de sorte qu’il convient de les lire avec aisance.À revoir : Les entiers et leur représentation
Question 3Des unités précédentesQu’écrit
std::println("{}", 0u - 1);avec ununsigned intde 32 bits ?Ne tient pas compte du suffixeu: un type non signé n’a pas de valeurs strictement négatives.Confond l’arithmétique non signée, définie modulo , avec le dépassement signé.Croit que la soustraction s’arrête à la plus petite valeur du type ; elle fait le tour.L’arithmétique non signée se fait modulo : . Le résultat est défini, et c’est pourquoi aucun détecteur ne le signale. L’unité le retrouve dans les conversions d’une expression mixte et dans les opérateurs bit à bit, qui s’écrivent avec des types non signés.À revoir : Les entiers et leur représentation
Question 4Des unités précédentesUn programme exécute
int count{std::numeric_limits<int>::max()};puiscount = count + 1;. Que garantit la norme sur la valeur decount?Confond ce que l’on observe parfois avec ce que la norme garantit ; le retour au minimum est ce que font les types non signés, non les types signés.Ignore la limite du type : ce nombre ne tient pas dans unintde 32 bits.Le compilateur ne connaît pas les valeurs que le programme aura à l’exécution ; il compile presque toujours sans rien dire.L’addition a une précondition, que le résultat tienne dans le type, et hors d’elle la norme ne promet rien. Le détecteur du cours arrête le programme ; sans lui, n’importe quoi peut s’écrire. La leçon 3.3 réunit ce cas avec les autres de son espèce dans un catalogue.À revoir : Les entiers et leur représentation
Question 5Que valent et ?
Opère de gauche à droite sans tenir compte de la priorité du produit.Ignore les parenthèses de la seconde expression.Attribue à chaque expression la valeur de l’autre : inverse l’effet des parenthèses.Le produit lie plus fort que la somme : dans , on multiplie d’abord, et les parenthèses modifient cet ordre. C++ suit la même convention, et la leçon 3.1 l’étend à la division, au reste et à l’associativité, avec l’arbre de l’expression pour instrument.À revoir : Arithmétique
Question 6D’après le théorème de la division des mathématiques, avec le reste soumis à , quels sont le quotient et le reste de par ?
C’est ce que calcule C++, mais cela ne vérifie pas : le reste des mathématiques n’est pas strictement négatif.Ne vérifie pas l’identité : , et non .Ne vérifie pas non plus l’identité : .Le théorème exige avec , et ces deux nombres sont les seuls qui le vérifient. C++, en revanche, tronque le quotient vers zéro :-7 / 2vaut et-7 % 2vaut . La leçon 3.1 explique la différence et enseigne à obtenir le reste des mathématiques à partir de celui de C++.À revoir : Arithmétique
Question 7Quelle est la négation de « il pleut et il fait froid » ?
Nie chaque partie sans changer le connecteur : cela affirme beaucoup plus que la négation, car cela exclut aussi le jour sec et froid.Ne nie qu’une seule des parties.Dit la même chose que la deuxième option, avec la même erreur.La négation d’une conjonction est la disjonction des négations : c’est l’une des lois de De Morgan. Il suffit que l’une des deux choses manque pour que l’affirmation soit fausse. La leçon 3.2 applique la même loi aux conditions d’un programme.À revoir : Relations et logique
Question 8Qu’écrit
std::println("{}", 3 < 5);?Croit que la valeur logique s’écrit comme un nombre ; avec le marqueur{},std::printlnécrit le mot.Croit que l’expression s’écrit comme un texte ; ce qui s’écrit, c’est sa valeur.C’en est une : une comparaison est une expression de typebool.Une comparaison est une expression comme une autre : elle a une valeur, de typebool, etstd::printlnl’écrit sous la formetrueoufalse. La leçon 3.2 part de cette observation : une condition se calcule, et c’est pourquoi elle a une priorité, un arbre et une algèbre.À revoir : Relations et logique
Question 9Après
int a{5};etint b{a++ * 2};, que valentaetb?C’est une réponse honnête : la leçon 3.3 enseigne la différence entre la valeur d’une expression et son effet, et l’évaluation de sortie reposera la question.Oublie l’effet :a++incrémentea.Utilise la nouvelle valeur dea; l’incrémentation suffixe donne la valeur antérieure.L’expressiona++a une valeur, celle qu’avaita(5), et un effet, qui laisseaà 6. Le produit utilise la valeur, non l’effet. La leçon 3.3 enseigne à séparer les deux choses, et à reconnaître quand deux effets dans une même expression la laissent sans signification.À revoir : Affectation, effets de bord et comportement indéfini
Question 10Qu’écrit
std::println("{}", 2 ^ 3);?C’est une réponse honnête : la leçon 3.4 l’explique, et l’évaluation de sortie reposera la question.Lit l’accent circonflexe comme une puissance, comme dans la notation de nombreuses calculatrices ; en C++, ce n’en est pas une.Le lit comme un produit.En C++, l’accent circonflexe n’est pas la puissance, mais le OU exclusif bit à bit : et ne diffèrent que par le bit de poids 1, de sorte que le résultat est 1. C++ n’a pas d’opérateur de puissance ; la leçon 3.4 enseigne quand utiliserstd::powet quand un décalage.À revoir : Bits et bibliothèque mathématique
Chargement du contenu…