Aller au contenu principal

Prendre une décision

Ce que ce chapitre apporte

  • Écrire une comparaison et ranger son résultat dans une variable Boolean.
  • Choisir entre deux chemins avec le bloc If, et prévoir ce qui s'exécute dans chaque cas.
  • Organiser plusieurs cas avec des If imbriqués, dans un ordre qui ne laisse aucune valeur sans réponse.
  • Combiner des conditions avec and, or et not, en maîtrisant les priorités.
  • Construire un jeu de valeurs qui passe par chaque chemin et teste chaque seuil.

Un programme qui exécute toujours les mêmes formes dans le même ordre ne sait réagir à rien. Dès qu'une mesure dépasse un seuil, qu'une vanne est ouverte ou qu'une pièce sort de ses tolérances, il faut choisir un chemin. Ce chapitre apprend à écrire la question que pose le losange, à organiser plusieurs cas sans en oublier ni en compter deux fois, et à vérifier une décision là où elle se trompe le plus souvent : exactement au seuil.

Une question à réponse vraie ou fausse

Un capteur mesure la pression dans un réservoir d'air comprimé. La question « la pression dépasse-t-elle le seuil de sécurité ? » n'a que deux réponses possibles : oui ou non. Flowgorithm range ce genre de réponse dans une variable de type Boolean, qui ne peut valoir que true ou false.

Définition

Une comparaison confronte deux valeurs et produit un booléen : true si elle est vérifiée, false sinon. Le résultat peut être rangé dans une variable Boolean, ou utilisé directement comme condition d'un losange.

QuestionÉcriture recommandéeAutre écriture acceptée
égal à===
différent de!=<>
strictement inférieur, inférieur ou égal<, <=
strictement supérieur, supérieur ou égal>, >=
Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
MainReal pression, seuilBoolean surpressionseuil = 6.5Input pressionsurpression = pression > seuilOutput "Pression : " & ToFixed(pression, 1) & " bar"End

La comparaison pression > seuil produit un booléen, rangé dans surpression, qui apparaît en bleu-vert dans la fenêtre des variables. Exécuter pas à pas, puis relancer avec une pression de 5 : la variable change de valeur.

Un seul égal, ou deux

Flowgorithm accepte = et == pour comparer : l'affectation a sa propre forme, le rectangle, et ne s'écrit pas dans un losange. Python, lui, réserve = au rangement et == à la comparaison, et la confusion y est une erreur classique. Ce cours écrit ==, !=, and, or et not, les écritures de Python.

Le bloc If : deux chemins qui se rejoignent

Le losange porte une condition. Si elle vaut true, le programme prend la branche True, à droite ; si elle vaut false, la branche False, à gauche. Les deux chemins se retrouvent ensuite en un point de jonction, et le programme continue.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainReal pression, seuilseuil = 6.5Input pressionpression > seuilOutput "Pression normale"Output "Ouvrir la soupape de sécurité"Output "Contrôle terminé"End

False à gauche, True à droite. Relancer avec une pression de 5 pour passer par l'autre branche : la dernière sortie s'affiche dans les deux cas.

Avec la saisie 7.2, la console affiche « Ouvrir la soupape de sécurité » puis « Contrôle terminé » ; avec 5, « Pression normale » puis « Contrôle terminé ». Ce qui est placé après la jonction ne dépend pas de la condition : une forme qui ne concerne qu'un cas va dans sa branche, jamais après.

Une branche peut rester vide : le chemin existe, mais il ne fait rien. C'est le cas le plus fréquent en surveillance, où l'on n'agit qu'en cas d'anomalie.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainReal pression, seuilInteger alertesseuil = 6.5alertes = 0Input pressionpression > seuilOutput "Alerte surpression"alertes = alertes + 1Output "Alertes : " & alertesEnd

La branche False est vide. Avec 5, le programme passe directement à la jonction ; avec 7.2, il affiche l'alerte et compte une alerte de plus.

Plusieurs cas : des If imbriqués

Le niveau de charge d'une batterie de secours se classe en trois cas : critique sous 10 %, faible sous 30 %, correct au-delà. Un losange n'a que deux sorties ; pour trois cas, on place un second losange dans une branche du premier.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueFalseTrueMainInteger chargeInput chargecharge < 10charge < 30Output "Charge correcte"Output "Charge faible"Output "Charge critique"End

Le second test n'est posé que si le premier est faux : arrivé là, la charge vaut déjà au moins 10. Essayer 5, 25 puis 80.

Le second losange n'a pas besoin de vérifier charge >= 10 : il ne s'exécute que dans la branche False du premier, donc quand la charge n'est pas sous 10. C'est tout l'intérêt de l'imbrication : chaque test hérite de ce que les précédents ont éliminé.

L'ordre des tests compte

Inverser les deux tests (d'abord charge < 30, puis charge < 10) donne un programme qui s'exécute sans erreur et qui se trompe : avec une charge de 5, le premier test est déjà vrai, le programme affiche « Charge faible », et le cas critique n'est jamais atteint. Avec des seuils « inférieur à », tester du plus petit au plus grand.

Chaque valeur doit tomber dans un seul cas. Trois If indépendants, posés l'un après l'autre, ne le garantissent pas :

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueFalseTrueFalseTrueMainInteger chargeInput chargecharge < 10Output "Charge critique"charge < 30Output "Charge faible"charge >= 30Output "Charge correcte"End

Trois décisions indépendantes, toutes évaluées. Avec 5, la console affiche « Charge critique » puis « Charge faible » : deux diagnostics contradictoires.

Vers Python

Python écrit une cascade sans l'imbriquer visuellement, avec elif (« sinon si ») ; l'indentation remplace les branches du losange.

main.py
Sortie
>_ Prêt à exécuter…

Conditions composées

Un bain de traitement thermique est correct si sa température est comprise entre 60 et 80 °C. Cette phrase contient deux comparaisons : la température est au moins 60, et elle est au plus 80. and exige que les deux conditions soient vraies ; or se contente d'une seule ; not inverse.

aba and ba or bnot a
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue
Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainReal temperatureBoolean dansPlageInput temperaturedansPlage = temperature >= 60 and temperature <= 80dansPlageOutput "Régler le chauffage du bain"Output "Température correcte"End

Ranger la condition dans dansPlage lui donne un nom : le losange se lit comme une phrase, et la réponse peut resservir plus loin sans réécrire la comparaison. Essayer 59, 60, 80 et 81.

« Compris entre » ne s'écrit pas comme en mathématiques

60 <= temperature <= 80 n'est pas une double comparaison : une comparaison confronte deux valeurs, pas trois. La première produirait un booléen, et c'est ce booléen, et non la température, qui serait comparé à 80. « Compris entre » s'écrit toujours avec deux comparaisons reliées par and.

L'erreur inverse est plus sournoise, parce qu'elle ne provoque aucune erreur :

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainReal temperatureInput temperaturetemperature > 60 or temperature < 80Output "Régler le chauffage du bain"Output "Température correcte"End

Une condition toujours vraie. Avec 95, le bain est jugé correct : toute température est au-dessus de 60 ou au-dessous de 80, et aucune saisie ne mène à la branche False. Une plage se décrit avec and.

Les priorités

Une expression ne s'évalue pas de gauche à droite mais selon la priorité des opérateurs, de la plus forte à la plus faible : not, puis les calculs et &, puis les comparaisons, puis and, et enfin or. Conséquences :

  • capotOuvert or temperature > 90 and moteurActif se lit capotOuvert or (temperature > 90 and moteurActif). Avec capotOuvert à true, temperature à 95 et moteurActif à false, elle vaut true ; la version (capotOuvert or temperature > 90) and moteurActif vaut false. Dès que and et or se mêlent, écrire les parenthèses qui disent l'intention.
  • not est plus fort qu'une comparaison : not charge < 10 s'évalue (not charge) < 10, et not reçoit un nombre au lieu d'une condition. Écrire not (charge < 10), ou plus simplement charge >= 10.
  • Nier une comparaison stricte fait apparaître l'égalité : not (a > 10) équivaut à a <= 10, et non à a < 10. De même, not (a == b) équivaut à a != b.
Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainInteger chargeInput chargenot charge < 10Output "Charge suffisante"End

Un not sans parenthèses. Exécuter : le programme s'arrête sur le losange, car not s'applique au nombre charge. Ajouter les parenthèses autour de charge < 10 corrige l'erreur.

Les valeurs limites

Les règles métier s'écrivent en français, et c'est à la traduction que l'erreur se glisse. « Une pièce est refusée si sa masse dépasse 250 g » donne masse > 250 ; « refusée dès qu'elle atteint 250 g » donne masse >= 250. Les deux programmes répondent pareil pour 200 ou 300 g. Ils ne diffèrent qu'en un point : 250 exactement.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainReal masseInput massemasse > 250Output "Pièce acceptée"Output "Pièce refusée"End

« Refusée si la masse dépasse 250 g ». Exécuter avec 250 : la pièce est acceptée. Remplacer > par >= change ce seul cas.

Un test avec 200 et 300 ne dit rien de la frontière. Pour vérifier une décision, construire un jeu de valeurs qui :

  1. passe au moins une fois par chaque chemin de l'organigramme ;
  2. prend exactement chaque seuil, puis une valeur juste en dessous et une juste au-dessus.

Pour la batterie (seuils 10 et 30), un jeu suffisant, où chaque valeur vérifie quelque chose que les autres ne vérifient pas :

Charge saisieChemin attenduCe que la valeur vérifie
5Charge critiquepremier chemin
9Charge critiquejuste sous le premier seuil
10Charge faiblele premier seuil exactement
29Charge faiblejuste sous le second seuil
30Charge correctele second seuil exactement
80Charge correctedernier chemin

Chaque ligne s'obtient en relançant l'organigramme de la batterie avec la saisie correspondante. Si l'énoncé disait « critique jusqu'à 10 % inclus », la ligne 10 devrait donner « Charge critique », et c'est elle seule qui révélerait l'erreur.

Fil rouge : la cuve de traitement

Étape 3 : la cuve calcule son taux de remplissage (étape 2). Elle doit maintenant en tirer deux décisions.

  • Le diagnostic, trois cas donc deux If imbriqués : « Débordement imminent » au-dessus du seuil haut (90 %), « Niveau bas » en dessous du seuil bas (10 %), « Niveau normal » sinon.
  • La pompe de remplissage, une condition composée rangée dans une variable : autorisée seulement si le taux est sous le seuil haut et que la vanne de sortie est fermée. L'opérateur saisit l'état de la vanne (true si elle est fermée).
Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueFalseTrueFalseTrueMainReal rayon, hauteur, volumeLitres, capaciteLitres, tauxBoolean vanneFermee, pompeAutoriseeInput rayonInput hauteurInput volumeLitrescapaciteLitres = pi * rayon ^ 2 * hauteur * 1000taux = volumeLitres / capaciteLitres * 100Output "Taux de remplissage : " & ToFixed(taux, 1) & " %"taux > 90taux < 10Output "Niveau normal"Output "Niveau bas"Output "Débordement imminent"Input vanneFermeepompeAutorisee = taux < 90 and vanneFermeepompeAutoriseeOutput "Pompe de remplissage bloquée"Output "Pompe de remplissage autorisée"End

Étape 3 du fil rouge. Saisies proposées : rayon 1.5, hauteur 4, 26000 litres, vanne fermée. Relancer avec 12000 litres, puis avec la vanne ouverte (false).

Avec les saisies proposées, le programme affiche « Taux de remplissage : 92.0 % », « Débordement imminent » et « Pompe de remplissage bloquée » : la vanne est fermée, mais la cuve est trop pleine. Avec 12000 litres et la vanne fermée, il affiche « Taux de remplissage : 42.4 % », « Niveau normal » et « Pompe de remplissage autorisée ». Avec 12000 litres et la vanne ouverte, la pompe est bloquée.

Au seuil haut exactement, pour un taux de 90 % tout juste, le diagnostic dit « Niveau normal » (taux > 90 est faux) mais la pompe est bloquée (taux < 90 est faux aussi). Les deux décisions respectent leurs règles : « au-dessus du seuil » et « sous le seuil » excluent tous deux l'égalité. Ce cas limite sera testé à l'étape 6.

Exercices type

Un arbre usiné est conforme si son diamètre est compris entre 19,95 et 20,05 mm, bornes incluses. Un technicien écrit le test ci-dessous. Qu'affiche-t-il pour 19.95, 20 et 20.05, et comment le corriger ?
Organigramme, tel que l'affiche Flowgorithm
FalseTrueMainReal diametreInput diametrediametre > 19.95 and diametre < 20.05Output "Rebut"Output "Conforme"End

Le test du technicien.

Les deux comparaisons sont reliées par and, ce qui est juste pour une plage. Mais elles sont strictes : pour 19.95, diametre > 19.95 est faux, donc toute la condition est fausse. Le programme affiche Rebut pour 19.95, Conforme pour 20, Rebut pour 20.05.

Deux pièces conformes sont mises au rebut, et un essai avec 20 seulement ne l'aurait jamais montré. « Bornes incluses » se traduit par diametre >= 19.95 and diametre <= 20.05 : avec cette condition, les trois saisies donnent « Conforme ». Seuls les deux seuils pris exactement révèlent la différence.

Au péage d'un pont, un véhicule léger (catégorie 1) paie 4 € le jour et 3 € la nuit ; un poids lourd (catégorie 2) paie 10 € le jour et 7 € la nuit. La nuit commence à 22 h et finit avant 6 h. Construire l'organigramme qui lit la catégorie et l'heure (entier de 0 à 23), puis donner le tarif affiché pour un poids lourd à 22 h et un véhicule léger à 5 h.

La nuit se décrit par une condition composée : l'heure est avant 6 ou à partir de 22. C'est bien or : aucune heure ne peut être à la fois inférieure à 6 et supérieure ou égale à 22. Ranger cette condition dans nuit évite de la réécrire dans chaque branche.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueFalseFalseTrueTrueMainInteger categorie, heure, tarifBoolean nuitInput categorieInput heurenuit = heure < 6 or heure >= 22categorie == 1nuittarif = 10tarif = 7nuittarif = 4tarif = 3Output "Tarif : " & tarif & " euros"End

La catégorie choisit la grille, la variable nuit choisit le tarif dans la grille.

Pour un poids lourd à 22 h, l'organigramme affiche Tarif : 7 euros ; pour un véhicule léger à 5 h, Tarif : 3 euros. 22 est un seuil : avec heure > 22, le poids lourd de 22 h paierait le tarif de jour. Autre limite du programme : toute catégorie autre que 1 passe par la branche False et paie comme un poids lourd, ce qu'une saisie de contrôle hors des valeurs prévues (3, par exemple) montre immédiatement.

Vérification

Vérification rapideon peut se reprendre

1.Pour charge = 30, laquelle de ces conditions est vraie ?

2.La branche False d'un If est vide. Que fait le programme quand la condition est fausse ?

3.Comment écrire « la cote est comprise entre 19,95 et 20,05, bornes incluses » ?

4.Quelle condition équivaut à not (a > 10) ?

5.Dans la cascade de la batterie (d'abord charge < 10, puis charge < 30), qu'affiche le programme pour une charge de 10 ?

6.Que vaut true and (false or true) ?

7.Pour quelles températures la condition temperature > 60 or temperature < 80 est-elle vraie ?

La méthode

  1. Traduire la règle mot à mot : « dépasse » et « au-dessus de » donnent >, « atteint » et « au moins » donnent >=, « compris entre » donne deux comparaisons reliées par and.
  2. Compter les cas : deux cas, un If ; trois cas, deux If imbriqués ; vérifier que chaque valeur possible tombe dans un seul cas.
  3. Ordonner les tests pour que chacun hérite de ce que les précédents ont éliminé.
  4. Nommer les conditions composées en les rangeant dans une variable Boolean, et parenthéser dès que and et or se mêlent ou qu'un not porte sur une comparaison.
  5. Placer chaque forme dans une branche si elle ne concerne qu'un cas, après la jonction si elle les concerne tous.
  6. Tester avec une valeur par chemin, puis chaque seuil exactement, et dérouler pas à pas quand un résultat surprend.

Synthèse

  • Une comparaison produit un Boolean, true ou false ; == compare, et reste l'écriture à préférer.
  • Le bloc If : branche False à gauche, True à droite ; une branche peut être vide ; ce qui suit la jonction s'exécute toujours.
  • Pour plusieurs cas, des If imbriqués : l'ordre des tests compte, et chaque valeur doit tomber dans un seul cas.
  • and exige les deux conditions, or une seule, not inverse ; priorités : not, calculs, comparaisons, and, puis or.
  • « Compris entre » s'écrit x >= a and x <= b ; x > a or x < b est vrai pour toutes les valeurs.
  • Les erreurs se cachent aux valeurs limites : tester chaque seuil exactement, et chaque chemin au moins une fois.

Mettre en pratique