< <= > >= ; les blocs sont délimités par l'indentation (4 espaces), jamais par des accolades.On exécute le programme suivant, ligne après ligne.
a = 7 b = 2 q = a / b d = a // b r = a % b
print(q), print(d) et print(r).a = a + 10 b = a a = 0
6 / 3 ? Et 6 // 3 ? Commenter.a. Trois divisions différentes.
/ est la division décimale : $q = 3{,}5$.// est le quotient de la division euclidienne : $d = 3$.% en est le reste : $r = 1$.On retrouve bien l'égalité de la division euclidienne : $7 = 2\times 3 + 1$, avec $0 \leqslant 1 \lt 2$.
b. On cherche à chaque fois le plus petit ensemble qui contient la valeur.
Rappel des inclusions : $\mathbb{N} \subset \mathbb{Z} \subset \mathbb{D} \subset \mathbb{Q} \subset \mathbb{R}$.
c. Une affectation se lit de droite à gauche : on calcule d'abord la valeur à droite, puis on la range dans la variable de gauche.
À la fin : $a = 0$ et $b = 17$. La copie a figé la valeur au moment où elle a été faite.
d. Attention au type du résultat.
6 / 3 renvoie 2.0 et non 2 : l'opérateur / renvoie toujours un nombre à virgule (type float), même quand la division tombe juste. 6 // 3 renvoie 2, un entier (type int).
💡 Mathématiquement $\dfrac{6}{3} = 2 \in \mathbb{N}$ dans les deux cas : le type Python décrit la manière de stocker le nombre, pas l'ensemble auquel il appartient.
On veut écrire un programme qui demande un nombre à l'utilisateur, puis affiche le plus petit ensemble parmi $\mathbb{N}$ et $\mathbb{Z}$ auquel il appartient — ou signale qu'il n'est pas entier.
x = float(input("Entrer un nombre : "))
if ... :
print("x appartient a N")
elif ... :
print("x appartient a Z")
else:
print("x n'est pas un entier")
On dispose de la fonction int(x), qui renvoie la partie entière de $x$ tronquée vers $0$ : int(2.7) vaut $2$ et int(-2.7) vaut $-2$.
x == int(x) et non x = int(x) ?a. « Être un entier » se traduit par « être égal à sa partie entière ».
if x == int(x) and x >= 0:
print("x appartient a N")
elif x == int(x):
print("x appartient a Z")
else:
print("x n'est pas un entier")
Le connecteur and exige que les deux conditions soient vraies en même temps : entier et positif.
b. On déroule les trois cas.
| $x$ | $x$ == int($x$) | $x \geqslant 0$ | Affichage |
|---|---|---|---|
| $5$ | vrai | vrai | appartient à $\mathbb{N}$ |
| $-3$ | vrai | faux | appartient à $\mathbb{Z}$ |
| $2{,}5$ | faux | vrai | n'est pas un entier |
c. C'est une conséquence directe de l'inclusion $\mathbb{N} \subset \mathbb{Z}$.
Tout entier naturel est aussi un entier relatif : si on testait $\mathbb{Z}$ en premier, $5$ déclencherait ce premier test et le programme n'afficherait jamais $\mathbb{N}$. Dans une cascade if / elif / else, on va toujours du plus petit ensemble vers le plus grand.
d. Ce sont deux instructions de natures totalement différentes.
x == int(x) est un test : il ne modifie rien et renvoie True ou False.x = int(x) est une affectation : elle écraserait $x$ par sa partie entière, et $2{,}5$ deviendrait $2$.💡 Remarque : la troncature vers $0$ de int ne gêne pas ici, car on se contente de tester une égalité.
On considère l'intervalle $I = [-2\,;\,5[$.
True si $x \in I$ et False sinon.def appartient(x):
return ...
appartient(-2) ? appartient(5) ? appartient(4.999) ?appartient_J pour $J = \left]-\infty\,;\,3\right]$.a. Un crochet fermé donne une inégalité large, un crochet ouvert une inégalité stricte.
def appartient(x):
return -2 <= x and x < 5
Python accepte aussi l'écriture condensée, plus proche de celle du cours :
def appartient(x):
return -2 <= x < 5
b. On teste les bornes, là où tout se joue.
appartient(-2) → True : le crochet est fermé en $-2$, la borne est dans $I$.appartient(5) → False : le crochet est ouvert en $5$, la borne est exclue.appartient(4.999) → True : on est juste en dessous de $5$.💡 Tester les deux bornes est le réflexe à avoir pour vérifier un programme d'appartenance : c'est exactement là que se cachent les erreurs de crochet.
c. $-\infty$ n'est pas un nombre : il ne peut pas apparaître dans un test.
def appartient_J(x):
return x <= 3
Il ne reste qu'une seule condition, celle de droite. C'est cohérent avec le cours : du côté de l'infini, le crochet est toujours ouvert, car aucune borne n'y est atteinte.
On pose $I = \left]-3\,;\,4\right]$ et $J = [0\,;\,7[$.
dans_I(x) et dans_J(x).dans_inter(x) et dans_union(x), testant l'appartenance à $I \cap J$ et à $I \cup J$. On les écrira à partir des deux premières, sans réécrire les inégalités.a. On traduit chaque crochet en inégalité.
def dans_I(x):
return -3 < x <= 4
def dans_J(x):
return 0 <= x < 7
b. « Et » pour l'intersection, « ou » pour la réunion.
def dans_inter(x):
return dans_I(x) and dans_J(x)
def dans_union(x):
return dans_I(x) or dans_J(x)
C'est la traduction littérale des définitions : $x \in I \cap J$ signifie « $x \in I$ et $x \in J$ », $x \in I \cup J$ signifie « $x \in I$ ou $x \in J$ » (au sens inclusif : l'un, l'autre, ou les deux).
c. Tableau des quatre valeurs.
| $x$ | dans_I | dans_J | dans_inter | dans_union |
|---|---|---|---|---|
| $-1$ | True | False | False | True |
| $0$ | True | True | True | True |
| $4$ | True | True | True | True |
| $5$ | False | True | False | True |
d. L'intersection retient les bornes les plus « serrées », la réunion les plus larges.
Chaque borne conserve le crochet de l'intervalle dont elle provient : le $0$ fermé vient de $J$, le $4$ fermé vient de $I$, le $-3$ ouvert de $I$ et le $7$ ouvert de $J$.
💡 La réunion est ici un intervalle parce que $I$ et $J$ se chevauchent ($I \cap J \neq \varnothing$). Avec $I = [0\,;\,1]$ et $J = [5\,;\,6]$, la fonction dans_union fonctionnerait toujours, mais $I \cup J$ ne serait pas un intervalle.
On veut compter les entiers relatifs contenus dans un intervalle. On rappelle que range(a, b) parcourt les entiers de $a$ inclus à $b$ exclu.
a. La borne de droite étant exclue, on écrit $12$ pour atteindre $11$.
for k in range(-4, 12):
print(k)
b. Un compteur se crée avant la boucle, s'incrémente dedans, s'affiche après.
n = 0
for k in range(-4, 12):
n = n + 1
print(n)
Le programme affiche $16$. Remarquer que n = n + 1 n'est pas une équation (elle n'aurait pas de solution !) mais une affectation : « $n$ prend la valeur de $n$ augmentée de $1$ ».
c. Ouvrir un crochet, c'est retirer une borne entière.
| Intervalle | Instruction | Nombre d'entiers |
|---|---|---|
| $[-4\,;\,11]$ | range(-4, 12) | $16$ |
| $\left]-4\,;\,11\right]$ | range(-3, 12) | $15$ |
| $\left]-4\,;\,11\right[$ | range(-3, 11) | $14$ |
Ici les deux bornes sont entières : chaque crochet ouvert fait donc perdre exactement un entier.
d. On généralise à partir du cas $[-4\,;\,11]$.
Vérification : $11 - (-4) + 1 = 16$. ✔
💡 Le « $+1$ » oublié est l'erreur classique : de $1$ à $10$ il y a $10$ entiers, pas $10 - 1 = 9$. On compte les bornes, pas les écarts.
$\sqrt{2}$ appartient à $\mathbb{R}$ mais pas à $\mathbb{Q}$ : il n'a pas d'écriture décimale exacte. On ne peut donc que l'enfermer dans un intervalle aussi petit que l'on veut. Le programme suivant procède par balayage au pas de $10^{-3}$.
n = 0
while (n / 1000) ** 2 < 2:
n = n + 1
print((n - 1) / 1000, n / 1000)
1.414 1.415. Qu'en déduire pour $\sqrt{2}$ ? Quelle est l'amplitude de l'intervalle obtenu ?a. Une boucle while répète tant que sa condition est vraie.
À chaque tour, $n$ augmente de $1$, donc le nombre testé $\dfrac{n}{1000}$ avance de $0{,}001$. On continue tant que son carré reste strictement inférieur à $2$ : la boucle s'arrête donc au premier entier $n$ pour lequel $\left(\dfrac{n}{1000}\right)^2 \geqslant 2$.
b. La boucle s'arrête pour $n = 1415$.
Le tour précédent ($n = 1414$) vérifiait encore la condition, donc :
Autrement dit $\sqrt{2} \in \left]1{,}414\,;\,1{,}415\right[$, intervalle d'amplitude $1{,}415 - 1{,}414 = 10^{-3}$. On dit que $1{,}414$ est une valeur approchée de $\sqrt{2}$ par défaut à $10^{-3}$ près, et $1{,}415$ une valeur approchée par excès.
c. Vérification à la main.
L'encadrement est bien confirmé.
d. Il suffit de changer le pas de balayage.
n = 0
while (n / 100000) ** 2 < 2:
n = n + 1
print((n - 1) / 100000, n / 100000)
On obtient $1{,}414\,21 \lt \sqrt{2} \lt 1{,}414\,22$, après $141\,422$ tours de boucle : cent fois plus de tours pour deux décimales de plus. Le balayage est simple mais coûteux.
💡 Pourquoi compter avec un entier $n$ plutôt qu'avancer directement par x = x + 0.001 ? Parce que les nombres à virgule de Python sont des valeurs approchées : on peut vérifier que 0.1 + 0.2 == 0.3 renvoie False ! Les erreurs s'accumuleraient à chaque tour. La machine ne manipule jamais $\mathbb{R}$, seulement un sous-ensemble fini de $\mathbb{D}$.