12. Expressions logiques▲
Le travail qu'un programme réalise est accompli par des expressions. Toute partie d'un programme qui produit une valeur ou un effet de bord est appelée une expression. La définition d'expression est très large, car même une constante comme 42 et une chaîne comme "bonjour" sont des expressions parce qu'elles produisent respectivement les valeurs constantes 42 et "bonjour".
Ne confondez pas produire une valeur avec définir une variable. Les valeurs n'ont pas besoin d'être associées à des variables.
Les appels de fonctions comme writeln sont également des expressions parce qu'ils ont des effets de bord. Dans le cas de writeln, l'effet se produit sur le flux de sortie et se traduit par l'ajout de caractères dans ce flux. Un autre exemple tiré des programmes que nous avons écrits est l'opération d'affectation qui affecte la variable dont le nom est présent à sa gauche.
Parce qu'elles produisent des valeurs, les expressions peuvent faire partie d'autres expressions. Ceci nous permet de former des expressions plus complexes à partir d'expressions plus simples. Par exemple, en supposant qu'il y a une fonction nommée TempératureActuelle() produisant la valeur de la température actuelle de l'air, la valeur qu'elle produit peut être directement utilisée dans une expression impliquant writeln.
writeln
(
"Il fait actuellement "
, TempératureActuelle
(
),
" degrés."
);
Cette ligne comporte quatre expressions :
- « Il fait actuellement »
- TempératureActuelle()
- « degrés. »
- l'expression writeln qui utilise les trois autres expressions.
Dans ce chapitre, nous allons voir un genre particulier d'expressions qui sont utilisées dans les instructions conditionnelles.
Avant d'aller plus loin, je voudrais faire un petit rappel sur l'opérateur d'affectation, en mettant cette fois l'accent sur les deux expressions qui apparaissent à sa gauche et à sa droite : l'opérateur d'affectation (=) affecte la valeur de l'expression de droite à l'expression de gauche (p. ex. : à une variable).
Température =
23
; // La valeur de Température devient 23
12-1. Expressions logiques▲
Les expressions logiques sont les expressions qui sont utilisées en arithmétique booléenne. Les expressions logiques sont ce qui fait qu'un programme prend des décisions comme « si la réponse est oui, j'enregistrerai ce fichier ».
Les expressions logiques ne peuvent prendre qu'une valeur parmi les deux possibles : false (faux) qui indique que l'expression est fausse et true (vrai) qui indique que l'expression est vraie.
J'utiliserai des expressions writeln dans les exemples qui suivent. Si une ligne se finit par true, cela voudra dire que ce qui est affiché sur la ligne est vrai. De même, false voudra dire que ce qui est sur la ligne est faux. Par exemple, si la sortie d'un programme est la suivante :
Il y a du café : true
Cela voudra dire qu'« il y a du café ». De même,
Il y a du café : false
voudra dire qu'« il n'y a pas de café ». Notez que le fait que « il y a » apparaît sur la gauche de la ligne ne veut pas dire que du café est présent. J'utilise la construction « Il y a… : false » pour dire « il n'y a pas » ou « c'est faux ».
Les expressions logiques sont utilisées de façon intensive dans les instructions conditionnelles, les boucles, les paramètres de fonctions, etc. Il est essentiel de comprendre comment elles fonctionnent. Heureusement, les expressions logiques sont très faciles à expliquer et utiliser.
Les opérateurs logiques qui sont utilisés dans les expressions logiques sont les suivants :
-
l'opérateur == répond à la question « est égal à ? ». Il compare les deux expressions à sa droite et à sa gauche et produit true si elles sont égales et false si elle ne sont pas égales. Par définition, la valeur que == produit est une expression logique.
Par exemple, supposons que nous ayons les deux variables suivantes :Sélectionnezint
joursDansUneSemaine=
7
;int
moisDansUneAnnée=
12
; -
Les expressions suivantes sont deux expressions logiques qui utilisent ces valeurs :
SélectionnezjoursDansUneSemaine
==
7
// true
moisDansUneAnnée==
11
// false
-
l'opérateur != répond à la question « n'est pas égal à ? ». Il compare les deux expressions contiguës et produit l'opposé de ==
.SélectionnezjoursDansUneSemaine
!=
7
// false
moisDansUneAnnée!=
11
// true
-
l'opérateur || veut dire « ou » et produit true si l'une ou l'autre des expressions qui sont à ses côtés est vraie.
Si la valeur de l'expression de gauche est true, il produit la valeur true sans même évaluer l'autre expression. Si l'expression du côté gauche est fausse, alors l'opérateur produit la valeur de l'expression de droite. Cet opérateur est similaire à la conjonction « ou » du français dans le sens où si l'une, l'autre ou les deux expressions sont vraies, alors il produit true.
Toutes les valeurs possibles des deux côtés de cet opérateur et leur résultat sont présentés dans cette table de vérité :Expression de gauche
Expression de droite
Résultat
false
false
false
false
true
true
true
false (non évalué)
true
true
true (non évalué)
true
Sélectionnezimport
std.stdio;void
main
(
){
// false veut dire « non », true veut dire « oui »
bool ilYADuCafé=
false
; bool ilYADuThé=
true
;writeln
(
"Il y a une boisson chaude : "
, ilYADuCafé||
ilYADuThé);}
Du fait qu'une des deux expressions est vraie, l'expression logique de ce programme produit true.
-
L'opérateur && signifie « et », et produit true si les deux expressions sont vraies.
Si la valeur de l'expression de gauche est fausse, il produit false sans même évaluer l'expression qui est à sa droite. Si l'expression de gauche est vraie, alors il produit la valeur de l'expression de droite. Cet opérateur est similaire à la conjonction « et » du français : si la valeur de gauche et la valeur de droite sont toutes les deux true, alors il produit true.Expression de gauche
Expression de droite
Résultat
false
false (non évalué)
false
false
true (non évalué)
false
true
false
false
true
true
true
Sélectionnezwriteln
(
"Je vais boire du café: "
, jeVeuxBoireDuCafé&&
ilYADuCafé);Le fait que les opérateurs || et && peuvent ne pas évaluer l'expression de droite est appelé « comportement raccourci ». Le seul autre opérateur qui a ce comportement est l'opérateur ternaire ? : qui sera vu dans un prochain chapitre. Tous les autres opérateurs évaluent et utilisent toujours toutes leurs expressions.
-
-
l'opérateur ^ répond à la question « l'un ou l'autre ? ». Cet opérateur produit true si seule une expression est vraie, mais pas les deux.
Expression de gauche
Expression de droite
Résultat
false
false
false
false
true
true
true
false
true
true
true
false
-
Par exemple, la logique qui représente mon choix de jouer aux échecs si un seul de mes deux amis arrive peut être codé ainsi :
Sélectionnezwriteln
(
"Je jouerai aux échecs : "
, jimEstApparu^
bobEstApparu); -
l'opérateur < répond à la question « est plus petit que ? » (ou « vient avant dans l'ordre de tri ? »).
Sélectionnezwriteln
(
"Nous gagnons : "
, leurScore<
notreScore); -
l'opérateur > répond à la question « est plus quand que ? » (ou « vient après dans l'ordre de tri ? »).
Sélectionnezwriteln
(
"Ils gagnent : "
, leurScore>
notreScore); -
l'opérateur <= répond à la question « est inférieur ou égal ? » (ou « vient avant ou au même endroit que ? »). Cet opérateur est l'opposé de l'opérateur >.
Sélectionnezwriteln
(
"Nous n'avons pas été vaincus : "
, leurScore<=
notreScore);] -
l'opérateur >= répond à la question « est supérieur ou égal à ? » (ou « vient après ou au même endroit que ? »). Cet opérateur est l'opposé de l'opérateur <.
Sélectionnezwriteln
(
"Nous n'avons pas gagné : "
, leurScore>=
notreScore); - l'opérateur ! veut dire « l'opposé de ». Différent des autres opérateurs logiques, il prend une seule expression et produit true si cette expression est fausse, et false si cette expression est vraie.
writeln
(
"Je marcherai : "
, !
ilYAUnVélo);
12-1-1. Grouper les expressions▲
L'ordre dans lequel les expressions sont évaluées peut être indiqué en utilisant des parenthèses pour les grouper. Quand des expressions entre parenthèses apparaissent dans des expressions plus complexes, les expressions entre parenthèses sont évaluées avant qu'elles puissent être utilisées dans les expressions dans lesquelles elles apparaissent. Par exemple, l'expression « s'il y a du café ou du thé, et aussi des cookies ou des pains au lait, alors je suis content » peut être codée de cette manière :
writeln
(
"Je suis content : "
,
(
ilYADuCafé ||
ilYADuThé) &&
(
ilYADesCookies ||
ilYADesPains));
Si les sous-expressions n'étaient pas entre parenthèses, l'expression serait évaluée selon les règles de priorité opératoire du D (qui ont été héritées du C). Comme dans ces règles && a une priorité plus grande que ||, écrire l'expression sans parenthèses ne serait pas évalué comme voulu :
writeln
(
"Je suis content : "
,
ilYADuCafé ||
ilYADuThé &&
ilYADesCookies ||
ilYADesPains);
L'opérateur && serait évalué en premier et l'expression entière aurait un sens équivalent à l'expression suivante :
writeln
(
"Je suis content : "
,
ilYADuCafé ||
(
ilYADuThé &&
ilYADesCookies) ||
ilYADesPains);
Cela a un sens complètement différent : « s'il y a du café, ou du thé et des cookies, ou du pain ; alors je suis content ».
12-1-2. Lire un booléen en entrée▲
Toutes les valeurs booléennes ci-dessus sont automatiquement affichées comme false et true. Ce n'est pas le cas dans la direction opposée : les chaînes "false" et "true" ne sont pas automatiquement lues comme valeurs false et true. Pour cette raison, l'entrée doit être d'abord lue en tant que chaîne et convertie vers une valeur booléenne.
Comme l'un des exercices suivants vous demande d'entrer "false" et "true" depuis l'entrée standard, j'ai été obligé d'utiliser des fonctionnalités du D que je ne vous ai pas encore expliquées. Je vais devoir définir une fonction qui convertit la chaîne en entrée en valeur booléenne. Cette fonction effectuera cette tâche en appelant to, qui est défini dans le module std.conv. (Vous pourrez voir des erreurs ConvException si vous entrez autre chose que "false" ou "true".)
J'espère que tout le code qui est dans les fonctions principales des programmes suivants est clair. read_bool() est la fonction qui contient de nouvelles fonctionnalités. Bien que j'ai inséré des commentaires pour expliquer ce qu'elle fait, vous pouvez ignorer cette fonction pour le moment. Malgré tout, elle est nécessaire pour que le programme marche et se compile correctement.
12-1-3. Exercices▲
- Nous avons vu ci-dessus que les opérateurs < et > sont utilisés pour déterminer si une valeur est inférieure ou supérieure à une autre valeur ; mais il n'y a pas d'opérateur qui réponde à la question « est entre ? » pour déterminer si une valeur se trouve entre deux autres valeurs.
-
Supposons qu'un programmeur ait écrit un code pour déterminer si une valeur est entre 10 et 20. Observez que le programme ne peut pas être compilé tel quel :
Sélectionnezimport
std.stdio;void
main
(
){
int
valeur=
15
;writeln
(
"est entre : "
,10
<
valeur<
20
);// ← ERREUR de compilation
}
-
Essayez d'utiliser des parenthèses autour de l'expression entière :
Sélectionnezwriteln
(
"Est entre : "
,(
10
<
valeur<
20
));// ← ERREUR de compilation
-
Observez qu'il ne peut toujours pas être compilé.
Sélectionnezwriteln
(
"Est entre : "
,(
10
<
valeur)<
20
);// ← compile mais FAUX
-
Observez que le programme marche maintenant comme attendu et affiche "true". Malheureusement, la sortie est trompeuse parce que le programme a un bogue. Pour voir les effets de ce bogue, remplacez 15 avec une valeur supérieure à 20 :
Sélectionnezint
valeur=
21
; -
Observez que le programme affiche toujours "true" même si 21 n'est pas plus petit que 20.
Astuce : se souvenir que le type d'une expression logique est bool. Vérifier qu'une valeur booléenne est inférieure à 20 ne devrait pas avoir de sens. -
Changez l'expression du programme selon cette logique et observez que ça affiche maintenant "true" comme attendu. Vérifiez également que l'expression logique marche correctement pour d'autres valeurs. Par exemple, quand la valeur est 50 ou 1, le programme devrait afficher "false" ; et quand c'est 12, le programme devrait afficher "true".
- si la distance jusqu'à la plage est inférieure à 10 et il y a un vélo pour tout le monde ;
si nous sommes moins de 6, avons une voiture et l'un de nous a le permis de conduire.
Tel quel, le programme suivant écrit toujours "true". Écrivez une expression logique qui affichera "true" quand l'une des conditions ci-dessus est vraie. (Lors de l'essai du programme, entrez "false" ou "true" pour les questions qui commencent par « Y a-t-il ».). N'oubliez pas d'inclure la fonction read_bool() quand vous testerez le programme suivant :
import
std.stdio;
import
std.conv;
import
std.string;
void
main
(
)
{
write
(
"Combien sommes-nous ? "
);
int
nombrePersonnes;
readf
(
" %s"
, &
nombrePersonnes);
write
(
"Combien y a-t-il de vélos ? "
);
int
nombreVélos;
readf
(
" %s"
, &
nombreVélos);
write
(
"À quelle distance est la mer ? "
);
int
distance;
readf
(
" %s"
, &
distance);
bool existeUneVoiture =
read_bool
(
"Y a-t-il une voiture ? "
);
bool existeUnPermis =
read_bool
(
"Y a-t-il un permis de conduire ? "
);
/*
Remplacez la valeur 'true' ci-dessous par une expression logique qui
produit la valeur true quand l'une des conditions
listées dans la question est satisfaite :
*/
writeln
(
"Nous allons à la mer : "
, true
);
}
/*
Cette fonction utilise des fonctionnalités qui seront
expliquées dans des chapitres suivants.
*/
bool read_bool
(
string message)
{
// Afficher le message
write
(
message, "(false ou true) "
);
// Lire une ligne comme une chaîne
string input;
while
(
input.longueur ==
0
) {
input =
chomp
(
readln
(
));
}
// Produire une valeur 'bool' depuis cette chaîne
bool résultat =
to!
bool
(
input);
// Retourner le résultat
return
résultat;
- Entrez des valeurs variées et vérifiez que l'expression logique que vous avez écrite fonctionne correctement.