Devoir surveillé d'informatique TSI – calcul formel, piles et arbres

Telechargé par khadija tigrioui
Royaume du Maroc
DEVOIR SURVEILLÉ D’INFORMATIQUE
INFORMATIQUE COMMUNE – FILIÈRE TSI
Durée : 2 heures
L’énoncé de ce problème comporte 5 pages de texte.
Les questions peuvent être traitées dans l’ordre souhaité, à condition d’indiquer clairement
leur numéro. Une fonction demandée dans une question peut être utilisée dans les questions
suivantes, même si elle n’a pas été écrite. Les réponses doivent être rédigées avec soin.
Si vous repérez ce qui vous semble être une erreur d’énoncé, signalez-le sur votre copie et
poursuivez en expliquant les initiatives que vous êtes amené(e) à prendre.
Tournez la page S.V.P.
TSI – Informatique Commune Année scolaire 2026/2027
Un mini-moteur de calcul formel
Piles, arbres syntaxiques et méthode de Newton
Introduction
Les logiciels de calcul formel (et, plus modestement, les calculatrices) doivent lire une expression
mathématique, la représenter en mémoire, puis l’évaluer, la simplier ou la dériver. On réalise dans
ce problème un petit moteur de calcul de ce type.
• Partie I : lecture d’une expression écrite en notation postxée, à l’aide d’une pile ;
• Partie II : algorithmes récursifs sur l’arbre de l’expression : évaluation, achage,
simplication, dérivation ;
• Partie III : application à la résolution numérique d’une équation f(x) = 0 par la méthode de
Newton.
Expressions. Les expressions considérées sont construites à partir :
• de constantes : des entiers naturels écrits en base 10 ;
• de la variable x;
• des quatre opérateurs binaires +,-,*et /(la division est la division réelle).
On suppose qu’aucune évaluation ne conduit à une division par zéro.
Arbre syntaxique. Une expression est représentée par un arbre binaire strict : les feuilles
portent les constantes et la variable, les nœuds internes portent les opérateurs ; le sous-arbre gauche
(resp. droit) d’un opérateur représente son opérande gauche (resp. droit). Comme en cours, l’arbre
vide est [] et un arbre non vide est [r, g, d]. Ainsi :
• une feuille est [c, [], []] où cest un entier, ou ['x', [], []] pour la variable ;
• un nœud interne est [op, g, d] où op est l’une des chaînes '+','-','*','/'.
On dispose des fonctions suivantes :
1def feuille(v):
2return [v, [], []]
3
4def est_feuille (a):
5return a[1] == [] and a[2] == []
6
7def est_constante(a):
8return est_feuille (a) and a[0] != 'x'
9
10 def appliquer(op , u, v):
11 if op == '+':
12 return u+v
13 eli f op == '-':
14 return u - v
15 eli f op == '*':
16 return u*v
17 els e :
18 return u/v
Rappels concernant le langage Python : il n’est pas possible d’utiliser les fonctions internes
min,max,sum,sort,sorted,eval, sauf mention contraire. Les instructions len(liste),
liste.append(e),liste.pop(), le tranchage (slicing), la concaténation, la méthode split des
© LEM6 - CASABLANCA 1Y.Kharbane
TSI – Informatique Commune Année scolaire 2026/2027
-
+
5*
+
1 2
4
3
Fig. 1 : L’arbre syntaxique E1de l’expression 5+(1+2)×4−3.
chaînes, la fonction abs et les conversions int et str sont autorisés. Les piles sont représentées
par des listes Python dont le sommet est le dernier élément : on empile avec append et on dépile
avec pop.
1 Notation postxée et piles
En notation postxée (ou notation polonaise inverse, NPI), un opérateur est écrit après ses
deux opérandes ; les parenthèses deviennent inutiles. Par exemple, (3 + 4) ×2s’écrit 34+2*et
l’expression E1de la gure 1 s’écrit :
512+4*+3-
Une expression postxée est donnée sous forme d’une liste de chaînes appelées lexèmes, obtenue
avec la méthode split :
>>> "5 1 2 + 4 * + 3 -".split()
['5', '1', '2', '+', '4', '*', '+', '3', '-']
Évaluation à l’aide d’une pile. On lit les lexèmes de gauche à droite. Un nombre est empilé.
Pour un opérateur, on dépile la valeur v(opérande droit), puis la valeur u(opérande gauche), et
l’on empile le résultat de u op v. À la n, la pile contient une seule valeur : le résultat. La gure 2
montre l’évolution de la pile pour E1.
5
5
1
5
1
2
5
1
2
+
5
3
4
5
3
4
*
5
12
+
17
3
17
3
-
14
lexème lu :
pile après
la lecture :
Fig. 2 : Évaluation de 512+4*+3-: état de la pile (sommet en haut) après chaque lexème.
□Q1 – Dessiner l’arbre syntaxique de l’expression postxée 23+74-*, puis donner sa valeur
en détaillant l’état de la pile après la lecture de chaque lexème, comme sur la gure 2. Écrire en
notation postxée l’expression (2 + x)×(x−1).
□Q2 – Écrire une fonction eval_npi(lex:list)->float qui renvoie la valeur d’une expression
postxée sans variable, donnée par la liste de ses lexèmes, en utilisant une pile. Sur l’exemple,
eval_npi("5 1 2 + 4 * + 3 -".split()) renvoie 14. Donner sa complexité en fonction du
nombre Lde lexèmes.
© LEM6 - CASABLANCA 2Y.Kharbane
TSI – Informatique Commune Année scolaire 2026/2027
Expressions correctes. Une liste de lexèmes peut ne pas représenter une expression correcte :
par exemple 3 + 4 (un opérateur manque d’opérandes) ou 3 4 5 + (il reste deux valeurs dans la
pile). On note hkla hauteur qu’aurait la pile après la lecture des kpremiers lexèmes, avec h0= 0 :
• si le k-ième lexème est un nombre ou la variable x, alors hk=hk−1+ 1 ;
• si c’est un opérateur, alors hk=hk−1−1(il dépile deux valeurs et en empile une).
On admet qu’une liste de Llexèmes est une expression postxée correcte si et seulement si hk≥1
pour tout k∈J1, LKet hL= 1.
□Q3 – Écrire une fonction est_correcte(lex:list)->bool qui teste cette condition sans
construire de pile, en un seul parcours de lex. Par exemple, est_correcte("3 + 4".split())
et est_correcte("3 4 5 +".split()) renvoient False, et est_correcte("2 3 + 7 4 -
*".split()) renvoie True.
□Q4 – Écrire une fonction taille_pile_max(lex:list)->int qui renvoie la plus grande des
hauteurs h1, . . . , hL, c’est-à-dire le nombre maximal de valeurs présentes simultanément dans la pile
lors de l’évaluation de l’expression correcte lex. Par exemple, taille_pile_max("5 1 2 + 4 * +
3 -".split()) renvoie 3.
Les expressions 1234+++et 12+3+4+représentent la même somme. Dessiner leurs
deux arbres, puis donner la valeur de taille_pile_max pour chacune. Laquelle des deux écritures
est préférable lorsque la pile est de taille limitée, comme sur une calculatrice ?
Construction de l’arbre. On remplace maintenant la pile de valeurs par une pile d’arbres : un
nombre ou la variable xdonne une feuille que l’on empile ; un opérateur dépile deux arbres dpuis
get empile l’arbre [op, g, d].
□Q5 – Écrire une fonction construire_arbre(lex:list) qui renvoie l’arbre syntaxique de
l’expression postxée (correcte) lex, qui peut contenir la variable x. Par exemple :
construire_arbre(['3', '4', '+', '2', '*']) renvoie
['*', ['+', [3, [], []], [4, [], []]], [2, [], []]]
2 Algorithmes récursifs sur l’arbre syntaxique
□Q6 – Écrire une fonction récursive evaluer(a, x:float)->float qui renvoie la valeur
de l’expression représentée par l’arbre alorsque la variable vaut x. Par exemple, si a =
construire_arbre("x x * 2 -".split()), alors evaluer(a, 3) renvoie 7. Justier que sa
complexité est linéaire en le nombre Nde nœuds de l’arbre.
□Q7 – Écrire une fonction récursive postfixe(a)->list qui renvoie la liste des lexèmes de
l’expression postxée représentée par l’arbre a(les constantes sont converties en chaînes avec str).
Sur l’arbre E1, elle renvoie ['5', '1', '2', '+', '4', '*', '+', '3', '-']. À quel parcours
de l’arbre correspond-elle ?
□Q8 – Écrire une fonction récursive infixe(a)->str qui renvoie l’écriture usuelle de l’expression,
chaque opération étant entourée de parenthèses. Sur l’arbre E1, elle renvoie '((5+((1+2)*4))-3)'.
Simplication. Les expressions produites automatiquement (en particulier par la dérivation)
contiennent souvent des calculs inutiles. On les simplie de bas en haut : on simplie d’abord les
deux sous-arbres d’un opérateur, puis on applique au nœud obtenu la première règle applicable
parmi les suivantes (edésigne une expression quelconque) :
R1 les deux opérandes sont des constantes c1et c2on remplace par la constante c1op c2
R2 e+ 0,0 + e,e−0,e×1,1×eon remplace par e
R3 e×0,0×eon remplace par la constante 0
© LEM6 - CASABLANCA 3Y.Kharbane
TSI – Informatique Commune Année scolaire 2026/2027
Si aucune règle ne s’applique, le nœud est conservé, avec ses sous-arbres simpliés.
*
+
x0
*
23
x0+23**
simplifier
R2 puis R1
*
x6
x6*
Fig. 3 : Simplication de (x+ 0) ×(2 ×3) en x×6.
□Q9 – Écrire une fonction récursive simplifier(a) qui renvoie un nouvel arbre, simplié selon
ces règles (l’arbre ane doit pas être modié). L’exemple de la gure 3 illustre son fonctionnement.
Donner un exemple d’expression égale à 0pour toute valeur de xque cette fonction ne simplie pas
en 0.
Dérivation formelle. La dérivée par rapport à xd’une expression se calcule récursivement : la
dérivée d’une constante est 0, celle de xest 1, et pour deux expressions uet v:
(u+v)′=u′+v′,(u−v)′=u′−v′,(u×v)′=u′×v+u×v′,u
v′=u′×v−u×v′
v×v.
□Q10 – Recopier et compléter la fonction récursive suivante, qui renvoie l’arbre de la dérivée de
l’expression aen appliquant ces formules sans simplication :
1def deriver(a):
2if est_constante (a):
3return feuille (0)
4if est_feuille(a): # la v a ria b l e x
5return feuille (1)
6op , u, v = a
7du = deriver(u)
8dv = deriver(v)
9if op == '+':
10 return ['+', du , dv]
11 if op == '-':
12 return ['-', du , dv]
13 if op == '*':
14 return ..............
15 return .............. # cas de la division
Dessiner l’arbre renvoyé pour l’expression x x *, puis l’arbre obtenu après application de
simplifier. Sur l’expression 3x*1x/+,infixe(simplifier(deriver(a))) renvoie
'(3+(-1/(x*x)))'.
3 Application : la méthode de Newton
On cherche à résoudre numériquement une équation f(x)=0, où fest donnée par l’arbre a
d’une expression. Dans toute cette partie, on prend comme exemple a = construire_arbre("x x
* 2 -".split()), qui représente f(x) = x2−2.
□Q11 – Écrire une fonction tableau_valeurs(a, xmin:float, xmax:float, n:int)->list qui
renvoie la liste des n+ 1 couples (xk, f(xk)), où xk=xmin +kxmax −xmin
npour k∈J0, nK. Par
exemple, tableau_valeurs(a, 0, 2, 4) renvoie
© LEM6 - CASABLANCA 4Y.Kharbane
1 / 6 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans l'interface ou les textes ? Ou savez-vous comment améliorer l'interface utilisateur de StudyLib ? N'hésitez pas à envoyer vos suggestions. C'est très important pour nous!