Terminaison #
Exercice 1 #
On dit qu’un programme termine s’il s’exécute correctement jusqu’au bout et s’arrête ou s’il plante (lève une exception).
Il ne termine pas s’il entre dans une boucle infinie.
Les programmes suivants terminent-ils ?
-
programme 1
n = 10 while n < 100: n = 2 * n -
programme 2
while n < 100: n = 2 * n -
programme 3
n = 0 while n < 100: n = 2 * n -
programme 4
capital = 0 while capital < 1000: capital = 1.2 * capital -
programme 5
capital = 10 while capital < 1000: capital = 1.2 * capital
Exercice 2 #
Citer la plage de valeurs pour lesquelles ces fonctions terminent et celle pour lesquelles elles ne terminent pas
Ces exemples de code sont volontairement mal écrits. Ne vous en inspirez pas et ne les exécutez pas !
-
fonction 1.
def compte_voyelle(mot: str) -> int: """Renvoie le nombre de voyelles dans mot""" voyelles = "aeiouy" i = 0 compteur = 0 while i < len(mot): lettre = mot[i] if lettre in voyelles: compteur += 1 return compteur -
fonction 2
def compte_a_rebour(n: int) -> None: """Affiche un compte à rebours""" while n != 0: print(n) n -= 1 -
fonction 3
def compte_a_rebour(n: int) -> None: """Affiche un compte à rebours""" while n > 0: print(n) n -= 1
Annales du baccalauréat #
Ce premier sujet revient sur la calculabilité et le problème de l’arrêt et montre qu’il ne suffit pas de chercher après le mot clé “while” dans un code Python pour déterminer qu’une fonction termine. Il aborde aussi l’algorithme de Boyer-Moore… Pas simple !
25-NSIJ1JA1 : 2025, Asie, Jour 1, Exercice 1 (6 points) #
Cet exercice porte sur la décidabilité, l’algorithmique et la programmation en Python.
En Python, on peut utiliser le triple guillemet pour écrire une chaîne de caractères sur plusieurs lignes. Par exemple, on peut définir une variable programme1 qui contient la chaîne de caractères correspondant à un petit programme Python de la manière suivante :
programme1 = """
x = 10
y = 10
while x > 0:
x = x - 1
y = y + 1
"""
De même, on peut définir la variable programme2 :
programme2 = """
def boucle_infinie():
while True:
pass # Ne rien faire
boucle_infinie()
"""
-
On suppose que l’on exécute le programme contenu dans la variable
programme1. Donner les valeurs dexet deyaprès exécution de ce programme. -
Expliquer pourquoi tout programme Python peut être vu comme une chaîne de caractères.
En Python, la fonction exec permet d’exécuter le programme correspondant à une chaîne de caractères passée en paramètre.
>>> exec("r = 42")
>>> r
42
>>> exec(programme1)
>>> x + y
20
>>> exec(programme2)
[ne termine pas]
On considère les quatre variables programme3, programme4, programme5, programme6 suivants :
programme3 = """
x = 10
while x != 0:
x = x - 2
"""
programme4 = """
x = 10
while x > 0:
x = x + 2
"""
programme5 = """
x = 10
while x < 0:
x = x + 4
"""
programme6 = """
x = 10
while x != 0:
x = x - 4
"""
- On exécute les variables
programme3,programme4,programme5,programme6avec la fonctionexec. Déterminer lesquelles terminent et lesquelles ne terminent pas.
On cherche à écrire une fonction arret telle que arret(programme) renvoie True si exec(programme) termine et False si exec(programme) ne termine pas. Cette fonction arret doit donc s’arrêter dans tous les cas.
- Indiquer ce que réalise le programme suivant et s’il permet de répondre au problème posé ci-dessus.
def arret_essai1(programme):
exec(programme)
return True
On suppose disposer d’une fonction recherche(mot, texte) qui renvoie True si une chaîne de caractères mot est présente dans une chaîne de caractères texte et False sinon.
- Expliquer succinctement le principe de l’algorithme de Boyer-Moore qui permet d’implémenter cette fonction
recherche.
Une idée est d’écrire une fonction qui décrète qu’un programme s’arrête s’il ne contient pas de while et ne s’arrête pas s’il en contient un.
-
Écrire une fonction
arret_essai2(programme)qui renvoieTruesi la chaîne de caractères"while"n’est pas utilisée dans la chaîne de caractèresprogrammeetFalsesinon. -
Montrer qu’il est possible que :
arret_essai2(programme)renvoieTruealors que le programme ne s’arrête pas ;arret_essai2(programme)renvoieFalsealors que le programme s’arrête.
Indication : il n’y a pas que les boucles while qui peuvent poser des problèmes de non terminaison.
Nos tentatives pour écrire une telle fonction arret sont restées vaines. Nous allons montrer qu’il est en réalité impossible d’écrire une telle fonction. On va supposer qu’une telle fonction arret existe. On va montrer que cette supposition aboutit à un paradoxe ce qui prouvera que la supposition est fausse.
- Écrire une fonction
terminaison_inversetelle que l’appelterminaison_inverse(programme)termine si la chaîne de caractèresprogrammereprésente un programme qui ne termine pas et ne termine pas si la chaîne de caractèresprogrammereprésente un programme qui termine. On pourra utiliser la fonctionboucle_infiniedeprogramme2ainsi bien sûr que la fonctionarretdont on a supposé l’existence.
On considère "terminaison_inverse(programme_paradoxal)" qui n’est rien d’autre qu’une chaîne de caractères, et on définit une variable que l’on appelle programme_paradoxal à laquelle on affecte cette chaîne de caractères :
programme_paradoxal = "terminaison_inverse(programme_paradoxal)"
-
Étudier si le programme paradoxal termine ou non, c’est-à-dire si
exec(programme_paradoxal)termine ou non. -
Indiquer ce que l’on peut conclure sur la fonction
arret. -
Expliquer si l’impossibilité d’écrire une telle fonction
arretest due aux limitations du langage Python.
Remarque #
Le sujet stipule “il n’y a pas que les boucles while qui peuvent poser des problèmes de non terminaison”
Voici quelques candidats sans while et le résultat obtenu lors d’une exécution avec Python classique (pas certain de ce qui se passe avec d’autres versions de l’interpréteur) :
Récursion infinie #
def f():
return f()
f()
s’arrête avec RecursionError: maximum recursion depth exceeded. Donc elle termine en pratique.
Appels cycliques indirects #
def a():
b()
def b():
a()
a()
même résultat : termine avec RecursionError: maximum recursion depth exceeded.
Boucles for avec des itérateurs (HP) #
def inf():
while True:
yield 1
for x in inf():
pass # Boucle infinie sans "while"
Ne termine pas, équivalent à while True. Dans l’état ça ne sert à rien.
Variante :
from itertools import count
for x in count():
pass
Blocage sur une ressource ou dans une attente : #
input("Tapez quelque chose : ") # Attend potentiellement pour toujours
Ne termine pas sans intéraction.
import time
while True:
time.sleep(1)
La même que while True: pass mais va consommer moins de ressources…
Importation circulaire #
exec('exec("exec(\'...\')")') # Peut être instrumenté en boucle infinie
On peut construire le même genre de programme avec import, eval ou exec…
Ne termine pas en théorie. Pas pris le risque de l’exécuter sur ma machine… désolé.
Multithreading #
En autorisant plusieurs fils d’exécution… alors il est facile de créer des boucles infinies sans while.