Informatique en CPGE Cours 1ère année

Informatique en CPGE
Cours 1ère année
Serge Bays
Lycée des Eucalyptus Nice
28 mars 2015
Table des matières
0.1
0.2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
5
6
6
6
7
7
7
8
8
8
8
8
9
9
Architecture
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.1 Définition : Ordinateur . . . . . . . . . . . . . . .
1.1.2 Définition : Informatique . . . . . . . . . . . . . .
1.2 Histoire . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Première génération . . . . . . . . . . . . . . . .
1.2.2 Deuxième génération . . . . . . . . . . . . . . . .
1.2.3 Troisième génération . . . . . . . . . . . . . . . .
1.2.4 Quatrième génération . . . . . . . . . . . . . . . .
1.3 Architecture matérielle . . . . . . . . . . . . . . . . . . .
1.3.1 Architecture de Von Neumann . . . . . . . . . . .
1.3.2 Une machine . . . . . . . . . . . . . . . . . . . .
1.4 Fonctionnement . . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Systèmes d’exploitation (OS = Operating System)
1.4.2 Organisation du disque dur . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
10
10
10
10
10
10
11
11
11
11
11
11
13
14
14
Algorithmique et programmation de base (partie 1)
2.1 Introduction . . . . . . . . . . . . . . . . . . . .
2.2 Les Langages . . . . . . . . . . . . . . . . . . .
2.2.1 Constituants . . . . . . . . . . . . . . .
2.2.2 Langage de programmation . . . . . . .
2.3 Algorithme . . . . . . . . . . . . . . . . . . . .
2.3.1 Définitions . . . . . . . . . . . . . . . .
2.3.2 Exemple . . . . . . . . . . . . . . . . .
2.4 Eléments de base en Python . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
15
15
16
16
16
17
17
17
17
0.3
0.4
1
2
Généralités . . . . . . . . . . . . . . . . . . . . . . . .
Le contenu théorique . . . . . . . . . . . . . . . . . . .
0.2.1 Algorithmique . . . . . . . . . . . . . . . . . .
0.2.2 Machine . . . . . . . . . . . . . . . . . . . . . .
0.2.3 Information . . . . . . . . . . . . . . . . . . . .
0.2.4 Langages . . . . . . . . . . . . . . . . . . . . .
La progression . . . . . . . . . . . . . . . . . . . . . .
0.3.1 Un système informatique - 2 semaines . . . . . .
0.3.2 Codage des nombres - 2 semaines . . . . . . . .
0.3.3 Algorithmique et programmation - 16 semaines .
0.3.4 Ingénierie numérique et simulation - 10 semaines
0.3.5 Bases de données - 6 semaines . . . . . . . . . .
Le fonctionnement . . . . . . . . . . . . . . . . . . . .
0.4.1 Matériel . . . . . . . . . . . . . . . . . . . . . .
0.4.2 Logiciels . . . . . . . . . . . . . . . . . . . . .
0.4.3 L’évaluation . . . . . . . . . . . . . . . . . . . .
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
http://mathematice.fr
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
19
20
Algorithmique et programmation de base (partie 2)
3.1 Boucles et itérations . . . . . . . . . . . . . . . .
3.1.1 Compteurs . . . . . . . . . . . . . . . .
3.1.2 Boucles itératives conditionnelle . . . . .
3.1.3 Boucles itératives . . . . . . . . . . . . .
3.1.4 Rupture de séquence . . . . . . . . . . .
3.2 Calculs . . . . . . . . . . . . . . . . . . . . . .
3.2.1 Bibliothèque mathématique . . . . . . .
3.2.2 Nombres complexes . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
22
22
22
22
23
25
25
25
26
2.5
3
4
5
6
7
2.4.1 Objets, expressions et types numériques
2.4.2 Variables et affectation . . . . . . . . .
2.4.3 Type str et fonction input . . . . . . . .
Instruction conditionnelle . . . . . . . . . . . .
Représentation des nombres
4.1 Codage de l’information . .
4.2 Codages des nombres entiers
4.2.1 Entiers naturels . . .
4.2.2 Entiers relatifs . . .
4.2.3 Programmation . . .
4.3 Nombres réels . . . . . . . .
4.3.1 Codage . . . . . . .
4.3.2 Programmation . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
28
28
28
28
30
31
31
31
32
Les fonctions
5.1 Définition d’une fonction . . . .
5.2 Espace et portée des variables .
5.2.1 Espace local . . . . . .
5.2.2 Portée d’une variable . .
5.2.3 Variables globales . . .
5.3 Algorithmes . . . . . . . . . . .
5.3.1 Solutions d’une équation
5.3.2 Recherche d’extremum .
5.3.3 Test de la monotonie . .
5.3.4 Intégrales . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
34
34
35
35
35
36
36
36
37
38
38
Les types composés
6.1 Types composés . . . . . .
6.1.1 Les n-uplets . . . .
6.1.2 Les listes . . . . .
6.2 Les tableaux et les matrices
6.2.1 Création . . . . . .
6.2.2 Utilisation . . . . .
6.2.3 Images . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
40
40
40
41
43
43
43
43
.
.
.
.
.
.
45
45
45
46
46
46
47
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Les fichiers
7.1 Gestion des fichiers . . . . . .
7.1.1 Ouverture d’un fichier
7.1.2 Fermeture d’un fichier
7.2 Ecriture et lecture . . . . . . .
7.2.1 Ecriture . . . . . . . .
7.2.2 Lecture . . . . . . . .
Serge Bays
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Lycée Les Eucalyptus
http://mathematice.fr
7.3
8
9
Fichiers binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Algorithmes : validité et complexité
8.1 Validité d’un algorithme itératif . . . . . . . . . . . . . . .
8.1.1 Invariants de boucle . . . . . . . . . . . . . . . .
8.1.2 Terminaison . . . . . . . . . . . . . . . . . . . . .
8.1.3 Un autre exemple . . . . . . . . . . . . . . . . . .
8.2 Complexité . . . . . . . . . . . . . . . . . . . . . . . . .
8.2.1 Mesure du temps d’exécution . . . . . . . . . . .
8.2.2 Borne asymptotique supérieure . . . . . . . . . . .
8.2.3 Niveaux de complexité . . . . . . . . . . . . . . .
8.3 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . .
8.3.1 Recherche séquentielle dans un tableau non trié . .
8.3.2 Recherche par dichotomie dans un tableau trié . .
8.3.3 Recherche d’un mot dans une chaîne de caractères
49
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
50
50
50
51
51
51
52
52
52
53
53
54
54
Résolution d’une équation : méthodes de dichotomie et de Newton
9.1 Recherche dichotomique . . . . . . . . . . . . . . . . . . . . .
9.2 Méthode de Newton . . . . . . . . . . . . . . . . . . . . . . . .
9.2.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2.2 Exemples . . . . . . . . . . . . . . . . . . . . . . . . .
9.2.3 Cas général . . . . . . . . . . . . . . . . . . . . . . . .
9.3 Complément . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3.1 Méthode de la sécante . . . . . . . . . . . . . . . . . .
9.3.2 Optimisation avec eval et exec . . . . . . . . . . . . . .
9.4 Utilisation de la bibliothèque scipy . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
56
56
57
57
57
59
60
60
60
60
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
10 Résolution numérique d’équations différentielles : méthode d’Euler
10.1 Méthode d’Euler . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2.1 Exemple 1 . . . . . . . . . . . . . . . . . . . . . . . . .
10.2.2 Exemple 2 . . . . . . . . . . . . . . . . . . . . . . . . .
10.2.3 Exemple 3 . . . . . . . . . . . . . . . . . . . . . . . . .
10.3 Complément . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
62
62
63
63
63
64
64
11 Résolution d’un système linéaire inversible : méthode de Gauss
11.1 Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.1.1 Création . . . . . . . . . . . . . . . . . . . . . . . .
11.1.2 Opérations classiques . . . . . . . . . . . . . . . . .
11.2 Autres opérations . . . . . . . . . . . . . . . . . . . . . . .
11.2.1 Recherche du pivot . . . . . . . . . . . . . . . . . .
11.2.2 Echange de lignes . . . . . . . . . . . . . . . . . .
11.2.3 Transvection . . . . . . . . . . . . . . . . . . . . .
11.3 Algorithme du pivot de Gauss . . . . . . . . . . . . . . . .
11.3.1 Résolution d’un système triangulaire . . . . . . . . .
11.3.2 Programme final . . . . . . . . . . . . . . . . . . .
11.4 Utilisation de Numpy . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
68
68
68
69
70
70
71
72
72
73
73
74
.
.
.
.
75
75
75
75
75
12 Bases de Données Relationnelles
12.1 Principes et architecture . . . . . . .
12.1.1 Le concept de client-serveur
12.1.2 Architecture trois-tiers . . .
12.2 Le modèle relationnel . . . . . . . .
Serge Bays
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Lycée Les Eucalyptus
http://mathematice.fr
12.2.1 Les relations . . . . . . . . . . . . . . . . .
12.2.2 Notion de clé primaire . . . . . . . . . . . .
12.2.3 La normalisation relationnelle . . . . . . . .
12.3 Algèbre relationnelle . . . . . . . . . . . . . . . . .
12.3.1 Vocabulaire des bases de données . . . . . .
12.3.2 Opérateurs usuels sur les ensembles . . . . .
12.3.3 Opérateurs spécifiques aux bases de données
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
76
77
77
78
78
78
78
13 Le langage SQL
13.1 Les requêtes d’interrogation . . . . . . . . . .
13.1.1 La logique d’interrogation . . . . . . .
13.1.2 Les opérations de base . . . . . . . . .
13.1.3 Le champ calculé . . . . . . . . . . . .
13.1.4 Les fonctions d’agrégation . . . . . . .
13.1.5 Les clauses de regroupement . . . . . .
13.2 Les requêtes de présentation des résultats . . .
13.2.1 Renommage de colonne . . . . . . . .
13.2.2 Ajout de texte . . . . . . . . . . . . . .
13.2.3 Le tri . . . . . . . . . . . . . . . . . .
13.3 Les requêtes de modification . . . . . . . . . .
13.3.1 Les requêtes d’insertion de données . .
13.3.2 Les requêtes de mise à jour de données
13.3.3 Les requêtes de suppression de données
13.4 Définition des données . . . . . . . . . . . . .
13.4.1 Suppression d’une table . . . . . . . .
13.4.2 Suppression d’un attribut . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
80
80
80
80
82
82
82
83
83
83
83
83
83
84
84
84
84
84
14 Les bibliothèques Numpy, Matplotlib, Scipy
14.1 Calculs avec des tableaux . . . . . . . . .
14.2 Tracé de courbes . . . . . . . . . . . . .
14.3 Algèbre linéaire . . . . . . . . . . . . . .
14.4 Calcul d’intégrales . . . . . . . . . . . .
14.5 Equation f(x)=0 . . . . . . . . . . . . . .
14.6 Equations différentielles ordinaires . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
85
85
86
89
90
90
91
Serge Bays
.
.
.
.
.
.
4
.
.
.
.
.
.
.
.
.
.
.
.
Lycée Les Eucalyptus
http://mathematice.fr
Introduction
0.1
Généralités
Depuis la rentrée 2013, l’informatique est devenue une discipline à part entière dans les Classes
Préparatoires aux Grandes Ecoles.
L’informatique et la numérisation sont omniprésentes dans la vie publique et pour les ingénieurs,
enseignants et chercheurs dans leur vie professionnelle. A partir de quelques concepts fondamentaux, on
réussit à conserver, à modifier et à transmettre toutes sortes de données à l’aide simplement de 0 et de 1. Un
même appareil permet actuellement de chercher et stocker des informations, de lire des livres, d’effectuer
des calculs, de regarder la télévision, d’enregistrer et d’écouter de la musique, de prendre des photos ou des
vidéos et de les visionner et même de téléphoner. Il y a quelques années, pour chacune des ces fonctions,
un appareil différent était nécessaire.
L’algorithmique et le développement de programmes informatiques sont entrés dans toutes les disciplines scientifiques. L’informatique joue un rôle semblable à celui des mathématiques avec son développement propre et ses applications trans-disciplinaires.
L’objectif principal de cet enseignement est de développer des compétences dans l’analyse et la modélisation d’un problème, d’une situation, dans la conception d’un algorithme et sa programmation afin
d’obtenir une solution et dans la communication qui permet le partage du travail effectué et des résultats
obtenus.
0.2
Le contenu théorique
Mon premier ordinateur portable (début des années 1990) avait la même taille que ceux d’aujourd’hui.
Mais à l’intérieur, le disque dur pouvait seulement contenir l’équivalent de deux minutes de musique (ou
de vingt minutes compressées en mp3) ; Windows en occupait le tiers, Word un quart et le reste permettait
d’avoir deux ou trois jeux et quelques fichiers. La mémoire était si petite que je ne m’en souviens plus. Ah
oui, l’écran était en noir et blanc. Actuellement les ordinateurs contiennent dix mille fois plus de données,
travaillent beaucoup plus vite, mais le fonctionnement est essentiellement le même ; il reste basé sur quatre
concepts fondamentaux qui existaient déjà avant la naissance de l’informatique et qui sont : Algorithme,
Machine, Langage et Information.
0.2.1
Algorithmique
Algorithmes de base
L’algorithmique est au programme de mathématiques à partir de la classe de seconde avec des algorithmes simples utilisant les notions de boucle, d’itération, de condition.
Algorithmes de recherche et de calcul
On développe des algorithmes de recherche dans une liste, un tableau trié, une chaîne et des algorithmes de calcul (moyenne, variance, zéro d’une fonction, valeur approchée d’une intégrale).
On étudie la complexité en mémoire ou en temps, la vitesse d’exécution d’un algorithme sur des
exemples simples et la notion d’invariant de boucle est introduite afin de vérifier la correction de segments
itératifs.
On s’efforce de bien distinguer les concepts "objet" algorithme et "outil" environnement de développement de leur "mise en œuvre" respective par l’implémentation dans un langage de programmation
comme Python et l’utilisation d’une interface graphique permettant d’éditer un texte (code source), de
l’interpréter, d’exécuter le programme, comme Idle pour Python.
Serge Bays
5
Lycée Les Eucalyptus
http://mathematice.fr
0.2.2
Machine
Architectures matérielles
Elles peuvent concerner différents types de machines : ordinateurs, réseaux, téléphone, télévision,
caméra, appareil photo, baladeurs, robots, . . .
Il s’agit d’identifier des composants de base tels que source d’énergie, mémoire, horloge, unité centrale, processeur, (les portes booléennes sont à la base du fonctionnement).
Un ordinateur, en général ne fonctionne pas tout seul ; des périphériques lui sont reliés par des ports
de communication et il s’agit de connaître leur rôle.
Fonctionnement
Pour fonctionner, la machine utilise un langage composé de suites d’instructions simples. Les systèmes d’exploitation (Unix, Linux, Windows, Mac Os, avec leurs différentes versions), qui sont liés au
processeur utilisé, permettent la communication entre la machine et l’utilisateur (qui peut être une autre
machine) et donc la gestion des répertoires et des fichiers, des applications ou des processus et du matériel.
0.2.3
Information
Comment est représentée puis stockée l’information, comment une machine la transforme, comment
on la transmet ?
Codage de l’information
Puisqu’une machine (numérique) travaille avec des nombres, l’information doit être au préalable
numérisée, que ce soit un nombre, un caractère, un texte, une image, un son, . . . . Mais une machine ne
connaît que le "0" et le "1".
Si toutes les informations sont codées avec des nombres entiers (y compris les approximations de
nombres réels), il s’agit alors d’avoir une représentation de ces nombres qui permette de les coder à l’aide
uniquement de "0" et de "1" pour pouvoir les stocker et les utiliser dans la machine ; c’est la représentation
binaire que l’on étudie puis le principe de représentation des nombres réels.
Stockage et traitement
Les données sont organisées dans des fichiers sous des formats différents. Les fichiers sont classés
sous forme d’arborescence avec dossiers, sous-dossiers, . . . . Ils peuvent aussi être compressés pour gagner
de la place. On utilise les outils du système d’exploitation.
Bases de données
Lorsque les données sont en très grand nombre, l’utilisation de bases de données relationnelles devient
indispensable et il est nécessaire d’avoir des outils de gestion performants. Les étudiants sont initiés à
différents concepts et au langage de requêtes SQL dans une perspective applicative à l’aide d’une interface
graphique.
0.2.4
Langages
Langages
De très nombreux langages permettent de communiquer avec une machine. On peut les répartir à
différents niveaux entre le langage machine et le langage naturel. Un langage de programmation permet
d’écrire un code source (compréhensible par l’utilisateur) qui sera traduit en langage machine (soit compilé,
Serge Bays
6
Lycée Les Eucalyptus
http://mathematice.fr
ce qui crée un fichier exécutable ensuite par la machine, soit interprété et exécuté par la machine en même
temps).
Programmation
On utilisera un environnement de développement (IDE = Integrated Development Environment, à ne
pas confondre avec Integrated Drive Electronics = Lecteur Électronique Intégré qui est souvent un disque
dur) qui est "Idle" pour le langage Python et qui permet de rassembler plusieurs tâches (création, édition,
modification d’un fichier source, interprétation, exécution d’un programme).
On insiste sur les différents types de données utilisées et la notion de variable ainsi que sur le rôle
capital des fonctions.
L’étudiant doit être capable de comprendre un programme, d’en concevoir à partir d’algorithmes
divers (en particulier ceux étudiés dans la partie algorithmique), de corriger ou d’améliorer un programme
existant et de se questionner sur la certitude qu’un programme fonctionne à toute occasion.
0.3
La progression
0.3.1
Un système informatique - 2 semaines
Architecture matérielle
Organisation :
• processeur (calcul-contrôle) <–> bus <–> mémoire
• avec entrées-sorties et une horloge
• et l’utilisation de portes booléennes
Les composants de base d’une machine numérique et leur rôle rexpectifs doivent devenir familiers
aux étudiants.
Système d’exploitation
On s’intéresse aux logiciels d’exploitation, (installation, fonctionnement, manipulation) ; ce sont des
"gros" programmes qui démarrent lorsqu’on allume la machine et permettent de gérer les périphériques,
les applications, les fichiers.
Environnement de développement
Présentation de l’environnement Idle pour Python. (C’est une GUI = Graphical User Interface ou
Interface Utilisateur Graphique qui pemet à l’utilisateur d’agir à l’aide de clics de souris plutôt qu’uniquement en mode texte).
0.3.2
Codage des nombres - 2 semaines
L’information est numérisée (traduite sous forme d’une suite de nombres). Comment représenter ces
nombres pour que la machine les comprenne ?
Nombres entiers
On étudie particulièrement la représentation binaire et on abordera le codage en hexadécimal.
Nombres réels
On étudie la représentation des nombres réels en "virgule flottante".
Serge Bays
7
Lycée Les Eucalyptus
http://mathematice.fr
Conséquences
On déduit des représentations précédentes des conséquences sur les limites et la précision des calculs.
0.3.3
Algorithmique et programmation - 16 semaines
Algorithmes de base
On revoit les algorithmes du programme de mathématiques en lycée.
Programmation de base
Les algorithmes sont transcrits dans un langage de programmation afin d’être exécutés sur machine.
Le langage utilisé est Python.
On étudie pour commencer des séquences d’instructions simples.
Algorithme de recherche, de calcul
On travaille sur des algorithmes plus complexes avec leur programmation et on étudie leur complexité
et leur vitesse d’exécution.
L’étudiant doit être capable de comprendre un programme simple, de le corriger ou de l’améliorer, de
savoir le modifier en fonctions des besoins et d’en concevoir.
Enfin, l’étudiant doit pouvoir se questionner sur la certitude qu’un programme fonctionne à toute
occasion (tests).
0.3.4
Ingénierie numérique et simulation - 10 semaines
La présentation de l’environnement de calcul numérique Scilab et des bibliothèques Numpy et Scipy
pour Python (1 ou 2 semaines) sera faîte assez tôt dans l’année suivant les besoins des autres disciplines.
Etude du développement d’algorithmes permettant la résolution numérique des problèmes étudiés et
mis en équations en Chimie, Physique, Maths et SI. Les étudiants peuvent comparer leurs programmes
avec ceux existants déjà.
0.3.5
Bases de données - 6 semaines
On présente le fonctionnement des bases de données relationnelles utilisant le langage SQL. Ceci se
fait par l’intermédiaire d’une interface graphique permettant d’appréhender plus simplement les différents
concepts et leur mise œuvre. On étudie le vocabulaire, les différents opérateurs et le concept client-serveur.
0.4
Le fonctionnement
Les activités pendant les deux heures d’informatique hebdomadaires consistent en des cours théoriques alternés avec des TP (en général, de la pratique sur ordinateur).
0.4.1
Matériel
Chaque étudiant travaille soit sur un poste (du lycée ou personnel) pour certaines activités, soit sur
papier, en particulier pour l’enseignement théorique. Chaque étudiant doit avoir une clé usb car il est
nécessaire de stocker à plusieurs endroits (au lycée, sur une clé et "ailleurs") le travail effectué pour éviter
des pertes éventuelles et irrémédiables de documents.
Deux livres références des éditions EYROLLES disponibles au lycée :
Informatique pour tous en classes préparatoires aux grandes écoles
Informatique et sciences du numérique (manuel de spécialité ISN en terminale)
Serge Bays
8
Lycée Les Eucalyptus
http://mathematice.fr
0.4.2
Logiciels
Tous les logiciels sont gratuits et disponibles en téléchargement afin que les étudiants puissent les
utiliser en dehors de la classe. La liste suivante présente ce qui peut être utilisé et n’est pas exhaustive.
– Programmation : Python (avec Idle).
– Calcul numérique : Scilab ou Python avec Numpy, Matplotlib et Scipy.
– Editeurs : EditHexa, Notepad++.
– Navigateur : Mozilla Firefox.
– Base de données : PHPMyAdmin (avec Base), ou Base de OpenOffice.
– Composition de documents : distribution LaTeX avec TeXnicCenter (Windows) ou Kile (Linux).
0.4.3
L’évaluation
L’année scolaire est découpée en deux semestres.
L’évaluation s’organise autour de tests de durées variables tout au long de l’année sur papier ou sur
machine, éventuellement sous forme de QCM, portant sur la théorie et sur la pratique.
Serge Bays
9
Lycée Les Eucalyptus
Chapitre 1
Architecture
1.1
Introduction
Un système informatique se compose :
• d’une partie matérielle (hardware) qui représente l’ensemble des composants de la machine,
• d’une partie logicielle (software) constituée des logiciels s’exécutant sur le matériel.
Les caractéristiques du matériel influent sur les performances des programmes et une bonne connaissance du fonctionnement interne de l’ordinateur permet de comprendre pourquoi certains algorithmes se
révèlent efficaces alors que d’autres sont mal adaptés, par rapport à une architecture donnée, et comment
en améliorer le fonctionnement.
1.1.1
Définition : Ordinateur
Un ordinateur est une machine électronique conçue pour effectuer des calculs et traiter des informations de manière automatique.
Le terme ordinateur a été inventé par Jacques Perret, professeur de philologie latine à la Sorbonne, à
la demande d’IBM France en 1955.
Un ordinateur est composé de plusieurs parties appelées :
• composants (carte mère, microprocesseur, barrette de mémoire, carte graphique)
• périphériques (disque dur, lecteur de DVD, clavier, souris, moniteur, ...).
Un périphérique est éloigné de la carte mère alors qu’un composant est en contact direct avec elle.
Pour certains, le terme périphérique fait plutôt référence à tout ce qui est externe au boitier : clavier,
souris, moniteur, imprimante... ce qui se trouve à la périphérie.
1.1.2
Définition : Informatique
Science de la recherche et du traitement de l’information effectué par un ordinateur. Elle comprend
l’ensemble des activités consistant à collecter, organiser et traiter de manière automatique les données par
un ordinateur.
Le terme informatique a été créé en mars 1962 par Philippe Dreyfus (Directeur du centre national de
calcul électronique de la société Bull dans les années 1950) à partir des mots information et automatique.
En anglais on emploie les termes Computer Science ou Computer Engineering.
1.2
1.2.1
Histoire
Première génération
Les premiers ordinateurs datent des années 1940, par exemple L’ENIAC (Electronic Numerical Integrator Analyser and Computer) aux USA, qui pesait 30 tonnes et était utilisé par l’armée, (programmé
par des femmes), ou bien le Z1, le Z2 et enfin le Z3, en Allemagne, programmables et utilisant le binaire.
10
http://mathematice.fr
Leur technologie était basée sur des tubes électroniques qui prenaient une place importante et dégageaient
beaucoup de chaleur. De plus ils coûtaient très cher. Leur puissance de calcul (unité : le Flop, floating point
operation per seconde) était comparable à celle d’une petite calculette d’aujourd’hui.
En 1951, c’est la conception du premier compilateur par Grace Hopper (1906 -1992), informaticienne
américaine, qui conçoit également le langage COBOL en 1959. Elle est à l’origine de l’expression "bug
informatique", (mention dans son journal de bord "first actual case of bug being found").
1.2.2
Deuxième génération
Vers la fin des années 1950, les tubes sont remplacés par des transistors avec un gain en puissance
de calcul. La consommation électrique, la taille et le prix sont réduits. Les ordinateurs rentrent dans les
universités.
1.2.3
Troisième génération
Dans les années 1960, c’est l’invention du circuit intégré, (puce en français, chip en anglais). Un
circuit remplace de très nombreux tubes ou transistors. La NASA (National Aeronautics and Space Administration) va pouvoir embarquer un ordinateur pour aller sur la lune.
1.2.4
Quatrième génération
A partir de 1971, le coeur de l’ordinateur est un ensemble de circuits intégrés appelé processeur.
Actuellement, la puissance de calcul d’un ordinateur personnel est d’environ 100 Gigaflops, (Giga = milliards). L’apparition des micro-ordinateurs a permis la démocratisation de l’informatique.
1.3
1.3.1
Architecture matérielle
Architecture de Von Neumann
L’architecture des ordinateurs actuels repose sur le modèle de Von Neumann.
John Von Neumann (1903-1957) était un mathématicien américain d’origine hongroise. Il travailla
comme consultant dans le projet ENIAC. Selon lui la mémoire de l’ordinateur, qui servait à stocker des
données, devait également stocker les programmes : c’est le concept de programme enregistré.
L’organisation était la suivante :
• une mémoire
• une unité de calculs CA (Central Arithmetical part) que nous appelons de nos jours ALU (Arithmetic and Logic Unit)
• une unité de contrôle CC (Central Control device)
• des entrées/sorties
• une horloge
La mémoire stocke des nombres (Standard numbers) et des instructions (Orders) sur 32 bits (64 bits
pour les ordinateurs les plus récents). Le bit 31 vaut 0 s’il s’agit d’un nombre et 1 dans le cas d’une
instruction.
On distingue aujourd’hui la mémoire dite centrale (RAM = Random Access Memory) de la mémoire
de masse (qui correspond aux périphériques tels que les disques durs).
Le processeur (CA + CC) communique avec la mémoire et les entrées/sorties par des "bus".
L’horloge est un circuit qui émet un signal périodique afin de synchroniser les circuits qui en ont
besoin (en particulier les circuits mémoires).
1.3.2
Une machine
• Le boîtier contient l’ensemble des composants, (également appelé Unité Centrale) ; c’est un élément important en raison de plusieurs facteurs :
Serge Bays
11
Lycée Les Eucalyptus
http://mathematice.fr
– les composants électroniques dégagent de la chaleur qui doit être évacuée sinon on risque une
surchauffe qui pourra engendrer des dégâts ;
– certains composants comme les disques durs, les ventilateurs font beaucoup de bruit, une bonne
isolation phonique apporte un certain confort.
– le boîtier est devenu un élément de mode.
• Un bloc d’alimentation convertissant le courant alternatif 220 V en courant continu 12 V et 5V.
(Une batterie rechargeable sur les ordinateurs portables).
•
–
–
–
–
–
–
Les périphériques externes d’entrée/sortie :
Moniteur
Clavier
Souris
Enceintes
Imprimante
Graveur externe
•
–
–
–
–
–
L’Unité Centrale :
Carte mère
Micro-processeur
Mémoire (RAM)
les périphériques internes : disque dur, lecteur DVD, carte graphique, carte réseau, . . .
Ports de communication
L’information est stockée en Mémoire :
• mémoire vive (RAM) accessible en lecture / écriture
• mémoire morte (ROM = Read Only Memory) accessible en lecture seule
• supports de stockage de masse (Disque Dur, clé usb, CDRom, Bandes)
Carte mère
La carte mère est un circuit imprimé qui permet de mettre en contact physique les différents composants et périphériques, et en particulier les trois éléments principaux de l’architecture de Von Neumann que
sont : le processeur, la mémoire, les entrées / sorties (périphériques).
C’est l’un des éléments essentiels d’un ordinateur. Les différents composants de la machine sont
reliés par des canaux de communication, appelés bus, permettant d’échanger l’information. La carte mère
(et notamment son chipset) détermine :
– la vitesse des différents bus
– le type de processeur qui peut être utilisé et la gamme de fréquences
– le type de mémoire qui peut être utilisé, ainsi que la taille maximale de la mémoire
On trouve donc sur une carte mère :
– le socket qui est le support où l’on connecte le processeur et qui détermine son type,
– des connecteurs pour la mémoire qui déterminent le type de mémoire à utiliser ainsi que la taille
de la mémoire maximale,
– différents ports :
• PCI (Peripheral Component Interconnect) pour les cartes d’extension graphique, son, réseau,
• AGP (Accelerated Graphics Port) pour les cartes graphiques hautes performances,
• IDE (Integrated Device Electronics) pour les périphériques internes, disques durs,
lecteurs/graveurs CD/DVD,
• USB (Universal Serial Bus), bus série externe destiné à remplacer et unifier les différentes
connexions (clavier, souris, imprimante qui utilisent les ports parallèle, port série),
Serge Bays
12
Lycée Les Eucalyptus
http://mathematice.fr
•
FireWire . . .
Notion de bus
Dans l’architecture de Von Neumann les différents composants échangent de l’information à travers
des canaux appelés bus.
Un bus se décompose en 3 parties :
• le bus d’adresses qui permet de spécifier à quelle adresse mémoire on désire accéder :
• le bus de données qui permet de spécifier d’envoyer ou de recevoir une donnée :
• le bus de commandes qui permet de spécifier si on effectue une lecture ou une écriture.
Sa largeur, (en nombre de bits ou d’octets) indique le nombre de bits qui sont transférés en même
temps et sa fréquence, (en hertz), indique la vitesse de transfert de l’information.
La bande passante est : fréquence × largeur.
Mémoires
On distingue la mémoire vive (ou RAM) de la mémoire morte (ou ROM).
La mémoire vive ou RAM (Random Access Memory) est une mémoire volatile : si l’on coupe l’alimentation, les données qu’elle contient sont perdues. On y stocke les programmes exécutés par le processeur et elle est accessible en lecture et en écriture.
• les registres sont les éléments les plus rapides. Ils sont situés au niveau du processeur et servent
au stockage des opérandes et résultats intermédiaires.
• la mémoire cache est une mémoire rapide de faible capacité destinée à accélérer l’accès à la
mémoire centrale en stockant les données les plus utilisées.
• la mémoire centrale contient les programmes (code + données) et est plus lente que les deux
mémoires précédentes.
• La mémoire d’appui est l’équivalent de la mémoire cache pour la mémoire de masse.
• la mémoire de masse est un support de stockage généralement de grande capacité et sert au
stockage et à l’archivage des informations.
Les mémoires mortes ou ROM (Read Only Memory) sont des mémoires non volatiles auxquelles on
accéde uniquement en lecture. Elles contiennent du code et des données qui ne sont pas amenés à changer
souvent. Les ROM contiennent généralement les routines d’accès de base aux périphériques.
Dans les ROM classiques, l’information contenue est enregistrée de manière irréversible lors de la
fabrication du circuit.
Le disque dur (hard drive) est un exemple de mémoire de masse, c’est l’un des composants (ou
périphérique) de l’ordinateur servant à conserver les données de manière persistante, contrairement à la
mémoire vive, qui est volatile. On qualifie également les média de stockage de grande capacité (clé usb)
de mémoire de masse.
1.4
Fonctionnement
Une machine exécute ce qu’on lui demande de faire et elle le fait sans aucune intelligence. Elle ne
comprend que le langage "binaire" et on communique avec elle en utilisant un langage de programmation
puis en passant par un "traducteur" (compilateur ou assembleur).
On sait représenter un nombre en base deux et on sait que dans un circuit avec un interrupteur, soit
il passe du courant si l’interrupteur est fermé, soit il n’en passe pas si l’interrupteur est ouvert. On peut
rajouter une lampe dans ce circuit et alors si la lampe est allumée, cela veut dire "un", et si elle est éteinte
cela veut dire "zéro". Ainsi une lampe correspond à un bit. On pourra donc représenter physiquement un
nombre avec plusieurs circuits en parallèle.
Serge Bays
13
Lycée Les Eucalyptus
http://mathematice.fr
1.4.1
Systèmes d’exploitation (OS = Operating System)
Un système d’exploitation est un ensemble de programmes qui sont lancés lorsqu’on allume un ordinateur. Tous les systèmes d’exploitation sont basés sur des concepts communs : des objets (les répertoires
et fichiers, les processus, le matériel interne et périphérique, . . . ) chacun avec son outil respectif (gestion
des fichiers, gestion des processus, gestion des périphériques). La mise en œuvre de ces concepts dépend
du système d’exploitation. Pour Windows, nous avons les formats Fat32 et NTFS avec l’outils "Explorateur de fichiers", les applications, processus ou services avec l’outil "Gestionnaire de tâches", les cartes
graphiques, les moniteurs, le réseau avec l’outil "Panneau de configuration".
Le système d’exploitation permet donc de :
• communiquer avec le disque dur afin d’y gérer les fichiers (leur attribuer un nom, les organiser
en arborescence, . . . ).
• gérer les périphériques à l’aide de "pilotes" (souris, écran, imprimante, . . . )
• exécuter simultanément plusieurs programmes (en partageant le temps alloué à chacun)
• gérer l’authentification de chaque utilisateur et ses droits d’accès sur les fichiers (lecture, écriture,
...)
1.4.2
Organisation du disque dur
Un programme permet d’installer sur le disque dur le système d’exploitation. Un partitionnement
peut être effectué ; ceci consiste à partager le disque en plusieurs parties afin de séparer par exemple les
programmes et les données.
Le disque a subi un "formatage de bas niveau" en usine lors de sa fabrication. Ceci a pour but d’organiser la surface du disque en éléments simples : pistes (cylindres), secteurs qui permettront de localiser
l’information. L’installation procède à un "formatage de haut niveau" qui permet d’organiser les pistes
et secteurs en un système de fichier qui sera géré par un système d’exploitation (Windows, Linux, Unix,
OS2, . . . ) : système de fichier NTFS pour Windows NT, XP, 7 ou 8 ; système Ext2, Ext3, pour Linux ... Le
système d’exploitation nous permet de procéder à un formatage de haut niveau autant de fois que l’on veut
par la suite.
Durant le formatage on regroupe les secteurs en blocs. Un bloc ou "cluster" devient alors la plus petite
unité d’allocation et on crée la FAT (File Allocation Table) qui contient la liste des clusters du disque ou de
la partition. Avec le système NTFS, un cluster correspond à quatre Ko (Kilo-octet). Donc pour un fichier
de 33,6 Ko, on réserve sur le disque 36 Ko soit 36 × 1024 = 36864 octets et pour un fichier de quelques
octets, on réserve le minimum, soit 4,00 Ko (4 096 octets).
Remarque : le partitionnement, effectué avant le formatage de haut niveau, permet de placer plusieurs
systèmes de fichiers différents (donc plusieurs systèmes d’exploitation) sur le même disque en utilisant les
différentes partitions.
Le secteur de démarrage (MBR = Master Boot Record) est le premier secteur d’un disque dur (cylindre 0, tête 0 et secteur 1), il contient la table de partition principale et le code qui, une fois chargé en
mémoire, va permettre d’amorcer le système (booter). Le MBR contient toutes les informations relatives
au disque dur (fabricant, numéro de série, nombre d’octets par secteur, nombre de secteurs par cluster,
nombre de secteurs, . . . ). C’est le secteur le plus important du disque dur, il sert au setup du BIOS à reconnaître le disque dur. Lorsqu’il est endommagé ou effacé par un virus le système d’exploitation ne peut plus
démarrer.
Serge Bays
14
Lycée Les Eucalyptus
Chapitre 2
Algorithmique et programmation de base
(partie 1)
2.1
Introduction
Informatique : traitement automatisée de l’information.
Algorithme : ensemble de règles opératoires dont l’application permet de résoudre un problème en
un nombre fini d’opérations.
Programme : séquences d’instructions et de données enregistrées sur un support et susceptibles d’être
traitée par un ordinateur.
Données : objets manipulés par le programme.
Le programme est la traduction d’un algorithme dans un langage de programmation qui impose une
syntaxe rigoureuse.
Objectif : écrire un programme dans un langage donné dont l’exécution permet de résoudre un problème.
Les étapes : A partir du problème à étudier, on commence par identifier et structurer les objets qui interviennent (les données), puis on détermine la méthode permettant de résoudre le problème (l’algorithme),
et enfin on combine le tout en un programme.
Lorsque l’algorithme est déterminé, il faut répondre à plusieurs questions avant de passer à la suite.
- L’algorithme est-il correct, donne-t-il la bonne réponse dans tous les cas ? Ce n’est pas toujours
facile de répondre à cette question.
- Est-ce que l’algorithme est suffisamment efficace : cela demande une analyse de complexité. On se
limitera aux cas faciles.
- Est-ce que l’algorithme est facile à implémenter ? Un algorithme simple est toujours préférable.
On peut alors passer aux instructions dans le langage de programmation choisi.
Une fois le programme écrit, on effectue des tests afin de vérifier que son comportement est conforme
à ce que l’on attend. Eventuellement on corrige et on recommence. En général, les erreurs de syntaxe, qui
sont les plus courantes, seront détectées et le programme ne s’exécutera pas. Le problème de la sémantique
est plus compliqué à régler ; le programme peut avoir un sens mais ne pas s’exécuter, ou ne jamais s’arrêter,
ou encore fonctionner mais ne pas donner le résultat attendu et ce dernier cas est le pire.
15
http://mathematice.fr
2.2
2.2.1
Les Langages
Constituants
Une langue :
- Syntaxe : des mots (noms, verbes, adjectifs, . . . ) et des règles de grammaire permettent de former
des phrases.
- Sémantique : une phrase bien formée n’a pas toujours un sens.
Catégories de langages :
- langue naturelle : syntaxe et sémantique ne sont pas rigoureuses. On peut se comprendre même avec
des phrases pas toujours correctes. Le récepteur est un être humain intelligent.
- langage informatique : syntaxe rigoureuse et rigide. La sémantique est complexe et difficile à bien
appréhender. Le récepteur est une machine sans intelligence.
- langage de description d’algorithme : une syntaxe moins rigide mais assez stricte pour ne pas donner
d’ambiguité sur le sens de ce qui est écrit.
2.2.2
Langage de programmation
Il existe des centaines de langages de programmation. Certain comme le C sont dits de "bas niveau",
c’est-à-dire assez proche du langage binaire de la machine et donc assez complexe, d’autres comme Python
sont dits de "haut niveau", plus éloigné du binaire donc plus souple, utilisant des opérations abstraites déjà
prévues dans le langage.
Le langage utilisé sera Python ; c’est un langage interprété, la séquence d’instructions ou code source
est exécutée directement. D’autres langage sont compilés, le code est d’abord traduit en langage machine.
Les programmes compilés sont en général plus rapide mais il est plus difficile d’y déceler d’éventuelles
erreurs.
Python est un langage général utilisable dans de nombreux domaines et portable (le même code source
peut être interprété sous Windows, linux, Mac OS, . . . ). C’est un langage qui a beaucoup évolué depuis
son introduction par Guido von Rossum en 1990. La dernière version est Python 3.4.1.
Un langage de programmation comprend :
– des commentaires : ils servent à expliquer (en langue naturelle) le comportement du programme
et ne jouent aucun rôle dans le comportement du langage. En Python, un commentaire est un texte
précédé du symbole #. Ce texte n’est pas interprété.
– des noms appelés identificateurs : ils désignent des variables, des fonctions,. . .
– des expressions : ce sont des combinaisons de noms avec des valeurs et des opérateurs. (par
exemple "x+2")
– des instructions : ce sont des commandes qui demandent de faire quelque chose. (par exemple
"z=x+2" demande d’affecter à z la valeur de x+2).
– l’indentation : cela consiste à laisser une ou plusieurs espaces au début des lignes. L’indentation
permet la lisibilité du programme ; en Python, elle fait partie de la syntaxe et remplace l’utilisation
d’accolades en C++ ou en Java.
Un programme source est une phrase de ce langage. C’est une suite de caractères, (un programme
écrit en Python est un script, soit une suite de définitions et d’instructions), pouvant être écrite dans un
éditeur de texte et compréhensible par l’humain. Un interpréteur pour Python, ou un compilateur pour
d’autres langages, permet ensuite de traduire et d’exécuter le programme sur une machine.
Serge Bays
16
Lycée Les Eucalyptus
http://mathematice.fr
2.3
Algorithme
2.3.1
Définitions
Le mot "algorithme" vient du nom de l’auteur persan Al-Khuwarizmi Mohammed (né vers 780 - mort
vers 850) qui a écrit en langue arabe le plus ancien traité d’algèbre (de l’arabe "al jabar" qui signifie "la
transposition" et du grec "arithmos" qui signifie "nombre") dans lequel il décrivait des procédés de calcul
à suivre étape par étape pour résoudre des problèmes ramenés à des équations.
Un algorithme peut se définir comme étant l’ensemble des règles et instructions à suivre, effectivement exécutables, permettant d’obtenir un résultat clairement défini en un nombre fini d’étapes.
Il ne faut pas confondre "algorithme et "programme". Un algorithme peut s’exprimer avec une notation indépendante de tout langage de programmation et il s’implémente, (c’est la "mise en œuvre"), dans
un programme qui lui est écrit dans un langage particulier compréhensible par une machine. Un algorithme
n’est pas compréhensible par un ordinateur qui ne peut qu’exécuter un programme. De plus, un algorithme
doit toujours donner une réponse après un nombre fini d’opérations, alors que l’exécution d’un programme
peut conduire à une boucle infinie et ne jamais s’arrêter.
Un algorithme se compose de données et d’instructions.
Dans les problèmes que nous allons résoudre, les données peuvent être de différents types. On rencontre les types nombre ou texte (chaînes de caractères), ou le type logique (vrai ou faux), ou le type
graphique (des points).
Les instructions à donner pour une exécution automatique doivent être suffisament simples pour être
traduites dans un langage de programmation. Les instructions élémentaires sont :
– les instructions d’entrée et de sortie : l’entrée (ou la lecture) des données peut se faire en interrogeant l’utilisateur ou par extraction à partir d’un fichier ; la sortie (ou l’écriture) peut se faire
par un affichage sur l’écran, une impression sur papier, une écriture dans un fichier ou bien les
résultats obtenus peuvent aussi rester en mémoire, (la sortie permet à l’utilisateur de voir les valeurs des variables après le traitement ou en cours de traitement si on veut contrôler l’exécution du
programme) ;
– les affectations et les calculs : l’affectation d’une donnée dans une variable consiste en la création
d’une zone de mémoire (dans la machine) à laquelle on donne un nom, ensuite diverses formules
permettent d’effectuer des calculs à l’aide d’opérations élémentaires, par exemple pour déterminer
la valeur d’une fonction pour une valeur donnée de la variable.
2.3.2
Exemple
Ecrire un algorithme de résolution dans R d’une équation du second degré.
2.4
Eléments de base en Python
Lorsqu’on ouvre Idle pour Python, on peut écrire directement des instructions qui sont interprétées à
chaque retour à la ligne. On peut aussi ouvrir une nouvelle fenêtre en allant dans le menu File, puis New
Window, (ou au clavier avec "ctrl + N") et entrer toutes les instructions souhaitées. On enregistre ensuite
le fichier par Save As . . . ; une fenêtre s’ouvre, où l’on choisit le dossier d’accueil et on entre un nom pour
le fichier avec l’extension .py ("nom.py"). On peut alors lancer le programme en allant dans le menu Run,
puis Run module ou en appuyant sur la touche F5 du clavier.
En sortie d’un programme, on peut écrire les résultats obtenus dans un fichier ; ceci sera étudié plus
tard. On peut aussi les afficher sur l’écran avec la fonction print. Par exemple print (’bonjour’) ou
Serge Bays
17
Lycée Les Eucalyptus
http://mathematice.fr
print (25+36) ou encore print (’La somme est égal à’,25+36) qui affiche "La somme
est égale à 61".
2.4.1
Objets, expressions et types numériques
Un programme en Python manipule des objets. Chaque objet a un type qui indique l’ensemble des
valeurs dont ils font partie et l’ensemble des propriétés qui les caractérisent. C’est le type qui définit ce que
le programme peut faire avec un objet.
Les types peuvent être scalaires ou non scalaires. Pour les scalaires, il y a :
• le type int (abréviation de l’anglais integer), pour représenter les nombres entiers illimités et on
écrit par exemple 5 ou 23214 ou −7 ;
• le type float pour représenter les nombres réels et on écrit par exemple 5.2 ou −26.721. Les
nombres du type float sont stockés dans la machine sous la forme de "nombres en virgule flottante"
entre −1, 7 × 10308 et 1, 7 × 10308 , ceci sera étudié plus tard.
• le type bool pour représenter les valeurs booléennes True et False ;
• le type None qui n’a qu’une seule valeur.
On forme des expressions en combinant les objets avec des opérateurs ; par exemple 5.2+3.4
représente l’objet 8.6 de type float. L’opérateur == est utilisé pour déterminer si deux expressions sont
égales et l’opérateur != pour déterminer si deux expressions ne sont pas égales.
La fonction type permet de déterminer le type d’un objet :
>>>type(5.2)
<class ’float’>
>>> type(-18)
<class ’int’>
Les opérateurs sur les types int et float sont :
– l’addition + , la soustraction - , la multiplication * , l’exponentiation ** dont le résultat est un
float si l’un des termes est un float et sinon un int ;
– la division / donc le résultat est toujours un float ;
– la division entière // , l’opération modulo % : utilisés avec des nombres entiers, on obtient le quotient et le reste, de type int, dans la division euclidiennne : 17//5=3 et 17%5=2 ou (-17)//5=-4 et
(-17)%5=3. Autre exemple : 7.4//3=2.0 (le résultat est un nombre entier mais de type float).
Les opérateurs précédents suivent les règles de priorité habituelles et on peut naturellement utiliser
des parenthèses.
Il existe aussi des opérateurs de comparaison qui ont le sens usuel : < , <= , > , >= .
Pour le type bool les opérations sont :
– a and b donne True si a et b sont True et False sinon ;
– a or b donne False si a et b sont False et True sinon ;
– not a donne True si a est False et False si a est True.
2.4.2
Variables et affectation
Une variable permet d’associer un nom avec un objet. Si on écrit pi = 3.14159, on lie le nom
pi à un objet de type float ; on a alors une variable dont le nom est "pi" et la valeur est 3,14159.
Une affectation associe le nom à gauche du signe = avec l’objet représenté par l’expression qui est à
droite du signe = ; par exemple aire=pi*5**2.
Serge Bays
18
Lycée Les Eucalyptus
http://mathematice.fr
Afin de faciliter la lecture d’un programme, il est important de bien choisir les noms utilisés. On peut
écrire :
a=3.14
b=5.3
c=a*b**2
mais il est préférable d’écrire, en ajoutant des commentaires si nécessaire :
# Calcul de l’aire d’un disque
pi=3.14
rayon=5.3
aire=pi*rayon**2
Il est important d’ajouter des commentaires qui seront ignorés par le compilateur mais qui seront bien
utiles à la compréhension si quelqu’un lit le programme ou si on le relit dans trois mois. Pour cela on utilise
le symbole # et le texte qui suit jusqu’à la fin de la ligne n’est pas interprété par Python.
Python autorise des affectations multiples : x, y = 3, 7 associe x à 3 et y à 7.
Ceci permet de faire l’échange : x, y = y, x de manière très simple (et bien utile !).
2.4.3
Type str et fonction input
Type str
Python n’a pas de type pour les caractères. Le type str, (abréviation de l’anglais string, chaîne en
français), est utilisé pour représenter les chaînes de caractères. (Un caractère est une chaîne de longueur
1). On peut écrire ’bonjour’ ou "bonjour".
Si on tape 3*’a’, on obtient ’aaa’ et si on tape ’a’+’b’ on obtient ’ab’. On dit que les opérateurs + et * sont surchargés, cela signifie qu’ils ont une action différente en fonction du type des objets
auxquels on les appliquent. Ici, ce n’est plus l’addition et la multiplication des nombres mais + permet la
concaténation de deux chaînes, * permet la répétition d’une chaine.
La fonction len permet de trouver la longueur d’une chaîne : len(’bonjour’) donne 7.
L’indexation permet d’extraire un caractère d’une chaîne. Attention, le premier caractère est indexé
par 0, donc ’bonjour’[2] donne ’n’, soit le troisième caractère. On peut aussi indexer à partir de la
fin de la chaîne : par exemple ’bonjour’[-1] donne ’r’.
Pour extraire une sous-chaîne, on utilise ’chaîne’[début:fin] ; l’extrait commence à l’index début et se termine à l’index fin-1 : par exemple, ’bonjour’[2:5] donne ’njo’. Et donc
’bonjour’[0:len(’bonjour’)] donne ’bonjour’.
Fonction input
La fonction input permet d’obtenir une chaîne de caractères entrée par l’utilisateur. Le code suivant
explique l’utilisation :
>>>nom=input(’Entrer votre nom :’)
Entrer votre nom : toto
>>> print(nom)
toto
Serge Bays
19
Lycée Les Eucalyptus
http://mathematice.fr
Afin de récupérer un nombre, il est nécessaire de procéder à une conversion :
>>> a=input(’Entrer un nombre entier : ’)
Entrer un nombre entier 5
>>> print(3*a)
’555’
>>> a=int(a) #conversion d’un type str en type int
>>> print(3*a)
15
La ligne a=int(a) permet de convertir le caractère ”5" en un nombre entier égal à 5. On peut aussi
écrire plus rapidement : a=int(input(’Entrer un nombre entier : ’)).
2.5
Instruction conditionnelle
Dans tous les exemples précédents, chaque instruction est exécutée dans l’ordre d’apparition. Les
programmes avec branchement apportent un intérêt plus important. L’un des plus simples utilise l’instruction conditionnelle : un test est effectué (une expression qui a la valeur True ou False) ; si la valeur est
True, alors un bloc de code est exécuté et un bloc optionnel peut être effectué si la valeur est False.
On utilise l’instruction "Si . . . alors . . . " , (If . . . then . . . ),
ou bien l’instruction "Si . . . alors . . . Sinon" (If . . . Then . . . Else).
L’algorithme correspondant s’écrit ainsi :
Si <condition> alors
... Instructions A ...
Sinon
... Instructions B ...
La traduction de l’algorithme en Python est :
if (condition) :
action1
action2
action3
else :
action4
action5
La condition peut s’écrire avec des opérateurs logiques, par exemple (a > 10 and a < 20).
Remarque : l’indentation est sémantiquement importante ; Python est très particulier dans cette utilisation (la plupart des autres langages utilisent des parenthèses ou des accolades). Toutes les instructions
au même niveau d’indentation appartiennent au même bloc.
Les programmes suivants ne sont donc pas identiques ; les commenter.
if x%2==0 :
print ("x est pair")
if x%3==0:
Serge Bays
20
Lycée Les Eucalyptus
http://mathematice.fr
print ("x est divisible par 6")
else :
print ("x est impair")
if x%2==0 :
print ("x est pair")
if x%3==0:
print ("x est divisible par 6")
else :
print ("x est impair")
Note : il existe une syntaxe plus compacte d’une alternative, par exemple :
min=x if x<y else y
Serge Bays
21
Lycée Les Eucalyptus
Chapitre 3
Algorithmique et programmation de base
(partie 2)
3.1
Boucles et itérations
3.1.1
Compteurs
Considérons l’instruction :
nombre=nombre+1
Cette instruction signifie : "évalue l’expression de droite et affecte la valeur obtenue à la variable de
gauche". Ceci permet donc d’incrémenter une variable de une unité et s’utilise souvent dans des boucles.
On écrit aussi (un peu moins lisible mais plus rapide) :
nombre += 1
3.1.2
Boucles itératives conditionnelle
On utilise l’instruction "Tant que" (While). Cette instruction s’emploie pour répéter une suite d’instructions lorsque le nombre de répétitions est inconnu. La suite d’instructions est répétée tant qu’une certaine condition est vraie : on commence donc par un test, si le test est True alors on parcourt le corps de
la boucle une fois ; ensuite on réévalue le test. Ce processus est répété jusqu’à ce que le test soit False ;
on passe alors à la suite du code.
Un exemple d’algorithme :
Variable x
x ...
Début Tant que <condition sur x>
... Instructions ...
Fin Tant que
L’implémentation en Python est :
22
http://mathematice.fr
x= ...
while (condition):
action1
action2
action3
La condition sur x peut être par exemple : (x<=100 and x >10).
Attention à toujours vérifier que la boucle ne va pas se répéter sans fin. Si la valeur de x n’est pas
modifiée dans le corps de la boucle, le test sera soit toujours False et la boucle n’est jamais exécutée, soit
toujours True et alors le programme ne se termine jamais.
Par exemple, l’algorithme suivant est-il correct ?
Entier i
i= 1
Début Tant que i>0
i = i+1
Fin Tant que
Que penser du programme suivant ? Et si on remplace la première ligne par x=1 ?
x=1.0
y=x+1
while y-x==1:
x=10*x
y=x+1
print (’x =’,x, ’y =’,y)
Si on exécute ce programme, on obtient x=1e+16 et y=1e+16, soit 1016 . Le même programme
exécuté sur une calculatrice donne 1012 ou 1014 ou . . . , suivant les modèles.
Explication : x est du type float. Or la taille et la précision des nombres de type float dans la
machine est limitée, (le codage des nombres sera étudié plus tard) ; donc il existe un grand nombre K,
par exemple K = 1016 , tel que 1 soit négligable par rapport à K et alors K + 1 est égal à K (pour la
machine !). La suite de nombres ainsi construite, 1, 2, 10, 11, 100, 101, . . . est croissante et majorée par
K ! Donc elle est convergente et le programme va bien se terminer. Par contre si x et y sont du type int,
le programme ne se termine pas car en Python les entiers sont illimités.
Application à la dichotomie
On cherche un nombre qui appartient à un ensemble de nombres ordonnés. La dichotomie consiste à
partager l’ensemble en deux ensembles de même taille puis à tester auquel des deux ensembles le nombre
appartient ; on recommence alors avec le nouvel ensemble et on reproduit ce processus tant que la taille
de l’ensemble est supérieure à la précision souhaitée. Cette méthode permet à chaque étape de diviser la
taille de l’ensemble, par exemple l’amplitude de l’intervalle, contenant la solution par deux. Donc en dix
étapes, la taille est environ mille fois plus petite puisque 210 ' 1000.
3.1.3
Boucles itératives
On souhaite afficher la table de multiplication par 13 :
Serge Bays
23
Lycée Les Eucalyptus
http://mathematice.fr
i= 1
Début Tant que i<=10
Afficher 13*i
i = i+1
Fin Tant que
Le programme en Python est le suivant :
i=0
while i<=10:
print(’13 fois’,i,’=’,13*i)
i=i+1
L’itération se fait sur une suite d’entiers bien déterminés. Une autre manière de produire le même
résultat est d’utiliser l’instruction "Pour" (For). Cette instruction s’emploie pour répéter par exemple n fois
une suite d’instructions lorsque n est connu à l’avance (pour déterminer un tableau de n valeurs d’une
fonction, pour le calcul de n termes d’une suite, . . . ).
L’algorithme est alors le suivant :
Entier i
Pour i = 0 à 10
Début
Afficher 13*i
Fin
Et l’implémentation en Python :
for i in range (0,11):
print(’13 fois’,i,’=’,13*i)
On peut aussi écrire for i in range (11):, car s’il n’y a pas de premier argument pour
range, le programme considère qu’il vaut 0.
De manière générale, on écrit :
for variable dans une séquence:
action1
action2
action3
Par exemple avec l’instruction for i in range (100): , la variable entière i va prendre successivement les valeur 0, 1, 2, . . . , 99, donc la boucle va s’effectuer 100 fois.
Voici une boucle qui calcule et affiche les carrés des entiers de 0 à 100 :
for i in range (101) :
print (i**2)
Serge Bays
24
Lycée Les Eucalyptus
http://mathematice.fr
La variable peut parcourir non seulement des entiers successifs mais aussi n’importe quel "itérable",
(suite ordonnée d’éléments), par exemple :
>>> for lettre in ’bonjour’:
print(lettre, end=’ ’)
b o n j o u r
3.1.4
Rupture de séquence
Une boucle peut être interrompue par l’instruction break :
for x in range (0,11):
if x==5:
break
print(x, end=’ ’)
0 1 2 3 4
Une boucle peut "sauter" une valeur avec l’instruction continue :
for x in range (0,11):
if x==5:
continue
print(x, end=’ ’)
0 1 2 3 4 6 7 8 9 10
3.2
3.2.1
Calculs
Bibliothèque mathématique
De nombreux petits programmes souvent utilisés existent déjà et on les trouve dans des bibliothèques.
Une bibliothèque pour Python (library en anglais, à ne pas confondre avec le mot français librairie qui se
dit book-shop en anglais) est composée de modules ou packages.
Le module math contient des constantes et des fonctions mathématiques usuelles. Pour une documentation, consulter http ://docs.python.org/3/ et vérifier en particuler le nom et l’utilisation des fonctions ;
par exemple la fonction mathématiques ln est notée "log".
Pour utiliser le module math, il faut l’importer dans notre programme :
>>> import math
>>> math.sqrt(2)
1.4142135623730951
>>> math.log(3)
1.0986122886681098
>>> math.exp(1)
2.718281828459045
>>> math.sin(math.pi/2)
1.0
Serge Bays
25
Lycée Les Eucalyptus
http://mathematice.fr
Afin de simplifier l’écriture des fonctions dans un programme, on peut utiliser une autre manière
d’importer des fonctions du module math :
>>> from math import sqrt, log, sin
>>> sqrt(8)
2.8284271247461903
>>> log(5)
1.6094379124341003
>>> sin(1.57)
0.9999996829318346
On peut aussi utiliser l’instruction import math as m et le nouveau nom du module math dans
notre programme est alors "m" ; ou bien l’instruction from math import* qui importe toutes les fonctions du module ; ceci peut être pratique mais cela signifie aussi que notre programme est rempli d’un grand
nombre de noms que nous n’utiliserons pas. Enfin, on peut aussi renommer les fonctions en écrivant par
exemple :
>>> from math import log, e
>>> ln=log
>>> ln(e)
1.0
Note : les fonctions permettant de générer des nombres aléatoires sont dans le module random ; la
fonction random() génère un flottant aléatoire dans l’intervalle [0; 1[, la fonction randint(a,b) avec
a et b entiers génère un entier aléatoire n tel que a≤ n ≤b .
On peur voir la doc http ://docs.python.org/3/library/random.html pour plus d’informations.
3.2.2
Nombres complexes
Python permet d’effectuer des calculs avec des nombres complexes. Le nombre imaginaire noté i en
mathématiques s’écrit j en Python et le nombre complexe 2 − 3i s’exprime par (2-3j) en Python. Attention,
le nombre complexe i s’exprime en Python par 1j (pas seulement j). Exemple d’écriture :
>>> c1=5-3j
>>> c2=3+1j
>>> p=c1*c2
>>> print (p)
(18-4j)
>>> type (p)
<class ’complex’>
>>> abs(3+4j)
5.0
On peut également définir un complexe par sa partie réelle et sa partie imaginaire, ou déterminer les
parties réelle et imaginaire d’un complexe donné ainsi que son conjugué :
>>> a=4
>>> b=-5
>>> c=complex(a,b)
Serge Bays
26
Lycée Les Eucalyptus
http://mathematice.fr
>>> c
(4-5j)
>>> c.real
4.0
>>> c.imag
-5.0
>>> c.conjugate()
(4+5j)
Il existe aussi un module mathématique consacré aux nombres complexes, le module cmath.
Serge Bays
27
Lycée Les Eucalyptus
Chapitre 4
Représentation des nombres
4.1
Codage de l’information
Les ordinateurs, comme d’autres appareils, permettent de mémoriser, de transmettre et de transformer
des nombres, des textes, des images, des sons, etc. Ils fonctionnent avec des petits circuits électroniques
qui ne peuvent être, chacun, que dans deux états représentés par 0 ou 1. Ce qui correspond à fermé ou
ouvert, faux ou vrai, . . .
Une telle valeur, 0 ou 1, s’appelle un booléen, un chiffre binaire (nombre en base 2) ou encore un bit
(binary digit), de symbole b. La mémoire des ordinateurs contient une multitude de ces circuits à deux états
appelé circuit mémoire un bit. Un circuit composé de plusieurs de ces circuits mémoire un bit, se décrit
par une suite finie de 0 et de 1, que l’on appelle un mot. Un mot de 8 bits est un octet. Le byte, de symbole
B, ou multiplet, est la plus petite unité adressable d’un ordinateur et correspond en général à un octet, (soit
1 B = 8 b).
Un nombre réel peut-être approximé avec la précision souhaitée par un nombre décimal qui peut
s’exprimer à l’aide de nombres entiers.
Pour coder un caractère, nous attribuons un nombre à chaque caractère selon des normes précises.
Ensuite, un texte est une suite de caractères, donc est codé par une suite de nombres.
Une image sur un écran d’ordinateur est composée de pixels (picture elements). Ce sont des petits
carrés qui composent un quadrillage. Si l’image est en couleurs, trois paramètres codent le niveau de
rouge, de vert et de bleu. C’est le système RGB, (red, green, blue) ou système RVB en français. Chacune
de ces trois composantes est codée par un nombre de 0 à 255.
De même il est possible de coder un son par une suite de nombres.
Donc de manière générale, l’information peut être codée par des nombres, c’est-à-dire "numérisée".
Il ne reste plus qu’à savoir représenter un nombre entier par une suite composées de 0 et de 1. Et un fichier
stocké sur un ordinateur ne sera qu’une suite plus ou moins longue composées de 0 et de 1.
4.2
4.2.1
Codages des nombres entiers
Entiers naturels
Représentation en base dix
On utilise pour les nombres entiers naturels la notation décimale à position. Pour cela, dix chiffres
sont nécessaires et suffisants : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
Par exemple, 3207 représente 3 milliers + 2 centaines + 0 dizaines + 7 unités.
3207 = 3 × 103 + 2 × 102 + 0 × 101 + 7
Pratiquement, si on dispose de 3207 objets identiques, et que l’on constitue des paquets de 10 objets, on
28
http://mathematice.fr
en obtient 320 et il reste 7 objets. Ensuite, avec les 320 paquets on forme des ensembles de 10 paquets, on
en obtient 32 ; puis on regroupe les 32 ensembles par 10, on obtient 3 groupes et il reste 2 ensembles.
On utilise la base dix tous les jours, mais d’autres bases sont envisageables.
La base deux
En base deux il n’y a que deux chiffres, 0 et 1, et le principe reste le même qu’en base dix.
Par exemple, pour 47 : on obtient 23 paquets de deux et 1 unités, puis les 23 paquets se regroupent en
11 paquets de paquets et il reste 1 paquets, ensuite . . .
47 = 23 × 2 + 1 = (11 × 2 + 1) × 2 + 1 = ((5 × 2 + 1) × 2 + 1) × 2 + 1 = . . .
47 = 1 × 25 + 0 × 24 + 1 × 23 + 1 × 22 + 1 × 21 + 1
Donc le nombre écrit 47 en base dix s’écrit 101111 en base deux. On peut utiliser la notation 1011112 .
Dans la notation binaire :
• le bit (ou chiffre) le plus à gauche est appelé bit de poids fort
• le bit (ou chiffre) le plus à droite est appelé bit de poids faible
Pour mesurer des quantité d’information, l’unité de base est le bit qui prend soit la valeur 0, soit la
valeur 1. Un ensemble de 4 bits consécutifs est appelé un quartet, un ensemble de 8 bits consécutifs est
appelé un octet (byte), deux octets consécutifs (16 bits) forment un mot (word).
C’est l’octet qui est utilisé comme unité de référence pour mesurer la capacité des mémoires.
Remarque : pour multiplier par deux un nombre écrit en base deux, il suffit d’ajouter un zéro à droite
du nombre :
10112 × 102 = 101102
Une base quelconque
On peut généraliser à une base quelconque les méthodes précédentes.
Pour écrire les entiers naturels en base k, on a besoin de k chiffres. Quand on a n objets, on les
groupe par paquets de k, qu’on regroupe à leur tour en paquets de k paquets, etc. Autrement dit, on fait
une succession de divisions par k, jusqu’à obtenir un quotient égal à 0. Ici encore, la multiplication d’un
nombre par k consiste à ajouter un zéro à droite du nombre.
La base seize est particulièrement intéressante. On a besoin de 16 chiffres notés : 0, 1, 2, 3, 4, 5 , 6,
7, 8, 9, puis A (dix), B (onze), C (douze), D (treize), E (quatorze) et F (quinze).
Si on travaille en base deux, l’écriture peut être très longue. Or un octet (huit bits) peut s’écrire
simplement en base seize. On partage l’octet en deux et chaque partie de quatre bits s’écrit avec un chiffre
de la base seize.
Démonstration : le nombre seize s’écrit 10000 en base deux et 10 en base seize : 100002 = 1016 ;
donc (a0 a1 a2 a3 a4 a5 a6 a7 )2 = (a0 a1 a2 a3 )2 × 100002 + (a4 a5 a6 a7 )2 = (b0 )16 × 1016 + (b1 )16 =
(b0 b1 )16
Par exemple le nombre écrit 11010101 en base deux s’écrit D5 en base seize. En effet 11010101 se
partage en 1101 et 0101 qui donnent respectivement D et 5 en base seize :
110101012 = 11012 × 100002 + 01012 = D16 × 1016 + 516 = D516
Dans l’ordinateur
Dans un ordinateur c’est le codage binaire qui est utilisé. Par exemple avec le nombre dont la représentation décimale est 59 :
59 = 1 × 32 + 1 × 16 + 1 × 8 + 0 × 4 + 1 × 2 + 1 × 1
59 = 1 × 25 + 1 × 24 + 1 × 23 + 0 × 22 + 1 × 21 + 1 × 20
59 = 1110112 .
Serge Bays
29
Lycée Les Eucalyptus
http://mathematice.fr
Avec des octets, soit huit bits, on peut représenter les entiers naturels de 0 (00000000 en base deux) à
255 (1111 1111 en base deux). Donc 59 sera représenté par 00111011.
Si on utilise seize bits, soit deux octets, on peut représenter les entiers naturels jusqu’à 65535 (1111
1111 1111 1111 en base deux) et dans ce cas 59 sera représenté par 0000000000111011.
Avec n bits, ce système permet de représenter les nombres entre 0 et 2n − 1, donc tout nombre k qui
s’ecrit :
k=
n−1
X
bi 2i
bi ∈ {0, 1}
i=0
Actuellement un entier est en général codé sur quatre octets (soit 32 bits).
Addition de nombres binaires
Pour additionner deux nombres binaires on procède comme en base 10.
A partir de 0 + 0 = 0, 1 + 0 = 0 + 1 = 1 et 1 + 1 = 10 on pose l’addition comme en base dix et
chaque fois qu’il y a 1+1, on écrit 0 et on retient 1.
Par exemple :
1 1 1 0 1
vingt-neuf
+ 1 1 0 0 1
vingt-cinq
1
1
retenues
1 1 0 1 1 0 cinquante-quatre
4.2.2
Entiers relatifs
On pourrait utiliser un bit pour le signe et les autres bits pour la valeur absolue. Mais cette méthode a
des inconvénients. On a préféré la méthode de représentation par complément à deux qui permet de réaliser
des opérations arithmétiques sans problème. Celle-ci consiste à réaliser un complément à un de la valeur,
puis d’ajouter 1 au résultat. Par exemple sur 6 bits, pour obtenir le codage de −5 :
000101 (codage de 5 en binaire sur 6 bits)
111010 (complément à un, on inverse chaque bit)
111011 (on ajoute 1) : représentation de −5 en complément à deux sur 6 bits.
Avec n bits, ce système permet de représenter les nombres entre −2n−1 et 2n−1 − 1, et tous les
nombres négatifs ont le bit de poids fort (bn−1 ) égal à 1.
Les entiers naturels de 0 à 2n−1 − 1 représentent les entiers relatifs positifs ou nul correspondants et
les entiers naturels de 2n−1 à 2n − 1 représentent les entiers relatifs négatifs de −2n−1 à −1.
Les machines actuelles utilisent 32 ou 64 bits (4 ou 8 octets).
Pour simplifier, avec un octet, soit huit bits, on peut représenter les entiers naturels n de 0 jusqu’à 255
et donc les entiers relatifs de −27 = −128 à 27 −1 = 127 ; les nombres n de 0 à 127, (de 0000 0000 à 0111
1111 en base deux), servent à représenter les entiers relatifs positif ou nul r avec r = n et les nombres n
de 128 à 255, (de 1000 0000 à 1111 1111 en base deux), représentent les entiers relatifs négatifs r avec
r = n − 256.
Le nombre n = 127 représente l’entier relatif r = 127 ;
le nombre n = 128 représente l’entier relatif r = 128 − 256 = −128 ;
le nombre n = 255 représente l’entier relatif r = 255 − 256 = −1.
Remarque 1 : un principe équivalent sur le cercle trigonométrique parcouru dans le sens direct de
degré en degré est de n’utiliser que des nombres positifs, soit, dans l’ordre, 0, 1, 2, . . . , 178, 179, 180, 181,
. . . , 358, 359 (ceci correspond aux entiers naturels), ou d’utiliser aussi des nombres négatifs, soit, dans
l’ordre, 0, 1, 2, . . . , 178, 179, -180, -179, . . . , -3, -2, -1.
Serge Bays
30
Lycée Les Eucalyptus
http://mathematice.fr
Remarque 2 : tous les nombres négatifs ont leur bit de poids fort égal à 1, alors que les nombres
positifs ont leur bit de poids fort égal à 0.
Remarque 3 : avec ce codage, si on peut faire effectuer par une machine l’addition de deux nombres
et le passage à l’opposé d’un nombre, on peut lui faire effectuer toutes les opérations classiques.
exemple sur un octet : 5 est codé par 00000101, -3 est codé par 11111101, donc l’addition 5+(-3) se
fait en ajoutant les nombres bit à bit, soit (1)00000010 qui est bien 2. (On ne garde que 8 bits.)
Remarque 4 : si on avait choisi de coder les négatifs avec simplement un bit de signe (0 pour + et 1
pour -), alors -3 serait codé par 10000011 et l’addition 5+(-3) bit à bit donnerait 10001000 qui coderait -8 !
4.2.3
Programmation
En Python, les entiers sont représentés par le type int (integer).
Les plupart des processeurs calculent avec des nombres binaires de taille limitée à 32 bits (ou 64
bits pour les processeurs les plus récents). Les langages de programmation en général font de même et les
calculs sur ces entiers, gérés directement par le processeur, sont très rapides. Python permet de calculer
avec des entiers de taille illimitée ; il gère lui-même l’encodage des nombres pour des tailles plus grandes
afin de ne transmettre au processeur que des nombres sur 32 bits et le programmeur n’a pas à s’en occuper.
La taille des entiers utilisés par Python n’est donc limitée que par la quantité de mémoire disponible dans
l’ordinateur. Mais plus les nombres sont grands et plus les calculs vont être décomposés par l’interpréteur
en calculs multiples sur des nombres plus simples et donc rallonger le temps de traitement.
4.3
Nombres réels
4.3.1
Codage
Définition
La norme IEEE 754 (Standard for Binary Floating-Point Arithmetic) définit la représentation de
nombres réels appelés flottants ou nombres à virgule flottante.
Un nombre réel est représenté par un nombre décimal, la meilleure approximation possible, qui s’écrit
sous la forme s m × 2n ou s est le signe du nombre, n son exposant et m sa mantisse. Cette représentation
est semblable à la notation scientifique des calculatrices, sauf qu’elle est en base deux et non en base dix.
En faisant varier l’exposant n, on fait "flotter" la virgule.
Le signe s est + ou −, l’exposant n est un entier relatif et la mantisse m est un nombre à virgule,
compris entre 1 inclus et 2 exclu. (En notation scientifique, c’est un nombre à virgule compris entre 1 inclus
et 10 exclu). Par exemple le réel 10 s’écrit +1, 25 × 23 ; le réel −0, 1875 s’écrit −1, 5 × 2−3 .
Les flottants IEEE peuvent être codés sur 32 bits ("simple précision" avec 1 bit pour le signe, 8 bits
pour l’exposant et 23 bits pour la mantisse) ou 64 bits ("double précision" avec 1 bit pour le signe, 11 bits
pour l’exposant et 52 bits pour la mantisse).
Si on code les nombres sur 64 bits :
• Le signe + est représenté par 0 et le signe − par 1.
• L’exposant n est un entier relatif compris entre −1022 et 1023 ; on le représente par l’entier
naturel n + 1023, (exposant décalé), qui est compris entre 1 et 2 046. Les deux entiers naturels 0 et 2 047
sont réservés pour des situations exceptionnelles (+∞, −∞, NaN, etc).
• La mantisse m est un nombre binaire à virgule compris entre 1 inclus et 2 exclu, comprenant 52
chiffres apres la virgule. Comme cette mantisse est comprise entre 1 et 2, elle a toujours un seul chiffre
avant la virgule et ce chiffre est toujours un 1 ; il est donc inutile de le représenter et on utilise les 52 bits
pour représenter les 52 chiffres apres la virgule.
Dans l’ordinateur les nombres seront alors codés par :
" signe exposant (décalé) mantisse (tronquée) "
Serge Bays
31
Lycée Les Eucalyptus
http://mathematice.fr
ces trois parties étant codées en binaire.
Exemple 1 : 10 = +1, 25 × 23
Le signe est + donc le premier bit vaut 0 ;
l’exposant est 3 donc l’exposant décalé est 3 + 1023 = 1026 et en binaire cela donne 100 0000 0010 ;
la mantisse est 1, 25 qui s’écrit en binaire 1,01. On garde la partie décimale 01 et on complète avec
des zéros.
Le codage de 10 est donc : 0 100 0000 0010 0100 0000 . . . 0000.
Exemple 2 : −0, 1875 = −1, 5 × 2−3
Le signe est − donc le premier bit vaut 1 ;
l’exposant est −3 donc l’exposant décalé est −3 + 1023 = 1020 et en binaire cela donne 011 1111
1100 ;
la mantisse est 1, 5 qui s’écrit en binaire 1,1. On garde la partie décimale 1 et on complète avec des
zéros.
Le codage de −0, 1875 est donc : 1 011 1111 1100 1000 0000 . . . 0000.
4.3.2
Programmation
En Python, les nombres réels ou nombres en virgule flottante sont du type float. Pour qu’une
donnée numérique soit considérée par Python comme étant du type float, il suffit que sa formulation
contienne un point décimal ou une puissance de 10 par exemple, 3.14 ou 1. ou .0001 ou 1e12 .
Précautions d’emploi
Les calculs en virgule flottante sont pratiques, mais attention :
– leur précision est limitée ; cela se traduit par des arrondis qui peuvent s’accumuler de façon gênante.
(Pour cette raison, en comptabilité les calculs ne sont pas effectués en virgule flottante).
– il n’y a aucun nombre dans un voisinage suffisament petit de zéro : une représentation flottante
possède une plus petite valeur négative, une plus petite valeur positive, et entre les deux le zéro,
mais aucune autre valeur ! Que vaut dans l’ordinateur la plus petite valeur positive divisée par 2 ?
Pour comparer deux nombres flottants on vérifiera donc que la valeur absolue de leur différence est
inférieure ou égale à une précision donnée.
– il y a un nombre maximal (max=1.7976931348623157e+308), donc une puissance de deux maximale (1023) et une puissance de dix maximale (308).
>>> 1.0e308
1e+308
>>> 1.0e309
inf
>>> 2.0**1023
8.98846567431158e+307
>>> 2.0**1024
Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
2.0**1024
OverflowError: (34, ’Result too large’)
Remarque : un problème d’overflow est responsable de l’autodestruction de la fusée Ariane 5, le 4
juin 1996, 39 secondes après le décollage ; la forte accélération de la fusée a provoqué un dépassement de
capacité lors du calcul des position et vitesse.
Il peut être tentant de réorganiser des expressions en virgule flottante comme on le ferait d’expressions
mathématiques. Cela n’est cependant pas anodin, car les calculs en virgule flottante, contrairement aux
Serge Bays
32
Lycée Les Eucalyptus
http://mathematice.fr
calculs sur les réels, ne sont pas associatifs. Par exemple, dans un calcul en flottants IEEE double précision,
(1050 + 1) − 1050 ne donne pas 1, mais 0. La raison est que 1050 + 1 est approximé par 1050 .
Serge Bays
33
Lycée Les Eucalyptus
Chapitre 5
Les fonctions
Nous avons déjà rencontré des fonctions, par exemple la fonction print, la fonction abs, des fonctions
du module math comme sqrt. Nous pouvons aussi définir et utiliser nos propres fonctions.
5.1
Définition d’une fonction
En Python la définition d’une fonction est de la forme :
def nomDeLaFonction(paramètres):
corpsDeLaFonction
def est un mot clé du langage qui dit à Python qu’une fonction va être définie, ce mot est suivi du
nom de la fonction puis d’une parenthèse, entourant un ou plusieurs paramètres séparés par des virgules
ou aucun paramètre, et enfin le caractère " :".
Le corps de la fonction est un bloc de code indenté par rapport à la ligne de définition.
Exemple : on étudie le mouvement vertical d’une balle lancée en l’air. Supposons que la position
verticale de la balle à l’instant t est donnée par y(t) = v0 t − 21 gt2 , où v0 est la vitesse initiale et g
l’accélération due à la gravité (environ 9,81).
On peut définir une fonction nommée "position" par :
def position(v,t):
return v*t-0.5*9.81*t**2
On appelle la fonction, en précisant la valeur des paramètres, par :
position(4,0.6)
Lors de l’appel, on affecte les valeurs 4 et 0.6 respectivement aux paramètres v et t de la fonction (on
dit aussi les arguments de la fonction) et le corps de la fonction est exécuté.
Si le corps de la fonction contient l’instruction "return" alors l’appel de la fonction est une expression
qui a donc une valeur. L’instruction suivante :
print(position(4,0.6))
34
http://mathematice.fr
permettra d’afficher le résultat : 0.6341999999999999.
S’il n’y a pas d’instruction "return" dans le corps de la fonction, alors l’appel de la fonction a la valeur
"None". Ce type de fonction s’appelle une procédure. Par exemple :
def successeur(n):
n+=1
print(n)
Il faut bien distinguer les arguments déclarés dans la définition de la fonction et les paramètres qui
sont utilisés au moment de l’appel de la fonction. Les paramètres peuvent avoir des noms différents ou
identiques à ceux des arguments ; cela n’a aucune importance, car les noms des arguments n’ont de signification qu’à l’intérieur de la définition de la fonction, et sont inconnus en dehors de la fonction. Le code
suivant fonctionne parfaitement :
def position(v,t):
return v*t-0.5*9.81*t**2
vitesse=4
temps=0.6
position(vitesse,temps)
5.2
5.2.1
Espace et portée des variables
Espace local
Si dans la définition d’une fonction on fait référence à une variable x, Python vérifie dans l’espace
local de la fonction si cette variable existe. Cet espace contient les paramètres qui sont passés à la fonction
et les variables définies dans son corps. Si la variable x n’existe pas dans l’espace local de la fonction,
Python va regarder dans l’espace local dans lequel la fonction a été appelée. Et là, s’il trouve bien la
variable x il peut l’utiliser.
5.2.2
Portée d’une variable
Quand Python trouve une instruction d’affectation, comme par exemple var = valeur1, il va
changer la valeur de la variable "var" dans l’espace local de la fonction. Mais cet espace local est détruit
après l’appel de la fonction.
Donc une fonction ne peut pas modifier, par affectation, la valeur d’une variable extérieure à son
espace local.
Dans le code suivant, la variable x utilisée dans la fonction est distincte de la variable x définie au
début du programme (x=3) et n’existe plus après l’appel de la fonction. Après l’instruction f(x), l’espace
local de la fonction f est détruit. On pourrait d’ailleurs remplacer "x" par n’importe quel autre identificateur
dans la définition de la fonction.
x=3
def f(x):
x+=2
print(x)
f(x) # affiche 5
print(x) # affiche 3
Serge Bays
35
Lycée Les Eucalyptus
http://mathematice.fr
De même la fonction d’échange suivante ne produit pas le résultat espéré :
a=2
b=5
def echange(x,y):
x,y=y,x
echange(a,b)
print(a,b) #affiche 2 5
5.2.3
Variables globales
Il existe un moyen de modifier, dans une fonction, des variables extérieures à celle-ci. On utilise pour
cela des variables globales. Pour déclarer à Python, dans le corps d’une fonction, que la variable qui sera
utilisée doit être considérée comme globale, on utilise le mot-clé global.
Le code suivant permet de modifier la variable x extérieure à la fonction.
x=3
def f():
global x
x+=2
print(x)
f() #affiche 5
print(x) #affiche 5
5.3
Algorithmes
Plusieurs algorithmes concernant l’étude des fonctions sont étudiés au lycée.
5.3.1
Solutions d’une équation
L’analyse mathématique, faite au préalable, permet grâce au théorème des valeurs intermédiaires
d’affirmer :
si f est continue croissante sur [a; b] et si k ∈ [f (a); f (b)],
ou si f est continue décroissante sur [a; b] et si k ∈ [f (b); f (a)],
alors l’équation f (x) = k admet une solution unique α dans [a; b] .
Méthode par dichotomie
Cette méthode permet de déterminer un encadrement de la solution α. A chaque étape l’amplitude
de l’intervalle contenant la solution est divisé par deux. En dix étapes, on gagne environ trois décimales
puisque 210 ' 1000. Exemple d’algorithme :
Variables et Initialisation
a et b, les bornes de l’intervalle [a ; b]
f, la fonction (f change de signe entre a et b)
m , milieu de l’intervalle "courant"
Traitement
Tant que b - a > 0.001
m prend la valeur (a+b)/2
Si f(m) et f(a) sont de même signe alors
Serge Bays
36
Lycée Les Eucalyptus
http://mathematice.fr
a prend la valeur m
sinon
b prend la valeur m
Sortie
a et b
On pourrait aussi utiliser une méthode par "balayage" ou une méthode par "calcul de valeurs aléatoires". Mais ces méthodes sont en général plus longues et sont plutôt utilisées pour la recherche d’extremum.
5.3.2
Recherche d’extremum
Algorithme 1 : déterministe à pas constant
Variables et Initialisation
a, b les bornes de l’intervalle d’étude
f, la fonction à étudier
N, le nombre d’intervalles et dx le pas
x, la valeur "courante" et y, la valeur de f(x)
min prend la valeur f(a)
max prend la valeur f(a)
dx prend la valeur (b-a)/N
x prend la valeur a
Traitement
Pour k de 1 à N
x prend la valeur x+dx
y prend la valeur f(x)
Si y>max alors
max prend la valeur y
Si y<min alors
min prend la valeur y
Sortie
Affiche min et max.
Algorithme 2 : tabulation « aléatoire » d’une fonction
Variables et Initialisation
a, b les bornes de l’intervalle
f la fonction à étudier
N le nombre d’images à calculer
min prend la valeur f(a)
max prend la valeur f(a)
Traitement
Pour k variant de 1 a N
x prend une valeur aléatoire entre a et b.
Si f (x) > max alors
max prend la valeur f(x)
Si f (x) < min alors
min prend la valeur f(x)
Sortie
Afficher min et max
Serge Bays
37
Lycée Les Eucalyptus
http://mathematice.fr
5.3.3
Test de la monotonie
Attention, cet algorithme peut permettre de montrer que la fonction n’est pas monotone ou que la
fonction peut être monotone mais dans ce cas il se peut qu’elle ait des variations de sens contraires sur
certains intervalles très courts.
Algorithme :
Variables et Initialisation
a, b les bornes de l’intervalle d’étude [a ; b]
f, la fonction à étudier
N, le nombre d’intervalles
x, les valeurs successives de la variable
dx prend la valeur (b-a)/N
sens prend la valeur signe de la différence f(b) - f(a)
x prend la valeur a
Traitement
Pour k variant de 1 à N
Si ( f (x+dx)-f(x) n’est pas du même signe que sens ) alors
Affiche "la fonction n’est pas monotone"
Affiche x et x+dx
Fin du programme
x prend la valeur x+dx
Affiche "La fonction semble monotone."
Sortie
Les affichages du traitement
5.3.4
Intégrales
On peut encadrer une intégrale pour une fonction monotone positive ou déterminer une valeur approchée d’une intégrale.
Encadrement
Soit f une fonction continue, positive et croissante sur [a; b] et n un entier strictement positif.
b−a
.
On partage [a; b] en n intervalles d’amplitude h =
n
Sur chaque intervalle [a + ih; a + (i + 1)h], où i varie de 0 à n − 1, on a l’encadrement
f (a + ih) ≤ f (x) ≤ f (a + (i + 1)h)
Z
a+(i+1)h
Donc hf (a + ih) ≤
f (x)dx ≤ hf (a + (i + 1)h), où à gauche et à droite, les produits
a+ih
sont des aires de rectangles.
On obtient alors l’encadrement suivant :
Z b
n−1
n−1
X
X
h
f (a + ih) ≤
f (x)dx ≤ h
f (a + (i + 1)h)
i=0
a
i=0
On peut alors écrire un programme afin d’effectuer ce calcul.
Serge Bays
38
Lycée Les Eucalyptus
http://mathematice.fr
Algorithme
VARIABLES
a, b, n, h DU TYPE NOMBRE
integ_inf, integ_sup DU TYPE NOMBRE
x DU TYPE NOMBRE
DEBUT ALGORITHME
Saisir a, b, n
h PREND LA VALEUR (b-a)/n
integ_inf PREND LA VALEUR 0
integ_sup PREND LA VALEUR 0
x PREND LA VALEUR a
POUR i variant de 0 à n-1
integ_inf PREND LA VALEUR integ_inf+f(x)
x PREND LA VALEUR x+h
integ_sup PREND LA VALEUR integ_sup+f(x)
FIN POUR
integ_inf PREND LA VALEUR h*integ_inf
integ_sup PREND LA VALEUR h*integ_sup
AFFICHER integ_inf, integ_sup
FIN ALGORITHME
Si la fonction f est simplement continue sur [a; b], on peut obtenir une valeur approchée de l’intégrale
en approximant f (x), sur chaque intervalle [a + ih; a + (i + 1)h], par f (a + (i + 1/2)h) : c’est la méthode
des rectangles.
Si on approche f (x), sur chaque intervalle [a+ih; a+(i+1)h], par [f (a + ih) + f (a + (i + 1)h)] /2,
c’est la méthode des trapèzes.
Serge Bays
39
Lycée Les Eucalyptus
Chapitre 6
Les types composés
6.1
Types composés
Définition : un objet de type composé est constitué de plusieurs objets ; nous étudions ici des suites
d’objets qui sont indexés par des entiers indiquant leur position dans la suite. Nous avons déjà rencontré le
type str pour les chaînes de caractères et nous allons étudier les types tuple et list.
6.1.1
Les n-uplets
Les n-uplets, (couples, triplets, quadruplets, . . . ), sont des objets de type tuple, (uplet en français
se dit tuple en anglais). Ces objets sont des suites ordonnées d’éléments, très semblables aux chaînes de
caractères et avec des fonctions communes. Les éléments d’un n-uplet peuvent être de n’importe quel type
et ne pas être tous du même type.
Pour construire un objet de type tuple, on utilise des paranthèses et les éléments sont séparés par des
virgules, par exemple :
a=(3, 5.2)
b=(’date’, 24, ’décembre’)
c=(a,b) # couple formé d’un couple et d’un
triplet
Attention : pour un 1-uplet, contenant par exemple l’unique élément entier 3, on écrit (3,). Il ne faut
surtout pas oublier la virgule.
L’accès à une composante ou une suite de composantes se fait comme pour les chaînes de caractères :
a[0] donne le nombre entier 3, b[2] donne le mot ’décembre’, b[0 :2] donne (’date’, 24).
Comme pour les chaînes de caractères, on peut concaténer, avec l’opérateur +, un n-uplet avec un
p-uplet pour obtenir un (n+p)-uplet : a+b est le quintuplet (3, 5.2, ’date’, 24, ’décembre’).
On obtient la longueur d’un n-uplet avec la fonction len comme pour les chaînes de caractères :
len(a+b) renvoie 5 et len(c) renvoie 2 (c’est un couple).
Affectation multiple : l’affectation a = 3,5.2 crée aussi le couple (3, 5.2). Inversement, on peut
déconstruire le couple par x,y =a ; on obtient x = 3 et y = 5.2. Ceci permet d’expliquer ce qui se passe
lorsqu’on écrit x,y = y,x : cette instruction crée d’abord un couple t = (y, x), (expression à droite du
signe =), puis déconstruit t en affectant à x le premier élément du couple et à y le deuxième. C’est pourquoi
on obtient ainsi l’échange des variables x et y.
Appartenance
On teste l’appartenance à un n-uplet comme pour les chaînes de caractères avec l’opérateur in :
40
http://mathematice.fr
>>> ’j’ in ’bonjour’
True
>>> ’décembre’ in b
True
>>> ’e’ in b
False
Note
Les objets de type tuple sont, comme les objets de type str, immuables : on ne peut pas changer un
élément de l’objet par une affectation. L’instruction b[1]=25 renvoie une erreur. Ceci est intéressant dans
certains cas, mais on peut aussi avoir besoin de pouvoir modifier la valeur d’un élément et il existe un type
d’objet pour cela, c’est le type list.
6.1.2
Les listes
Définition
Une liste, objet de type list, est d’une certaine manière un n-uplet dont on peut changer les valeurs
des éléments. C’est donc en particulier un ensemble ordonné d’éléments éventuellement hétérogènes. Une
liste en Python correspond à ce que l’on appelle un tableau dans plusieurs autres langages.
Syntaxe
Les éléments d’une liste sont séparés par des virgules et entourés de crochets. Les opérateurs fonctionnent comme pour les n-uplets. Par exemple :
liste1=[2,5,3,8]
liste2=[’vert’,’rouge’]
liste1[2]=’bleu’ #on change un élément de la liste
print(liste1) #affiche [2, 5, ’bleu’, 8]
liste3=liste1+liste2 # concaténation de deux listes
print(liste3) #affiche [2, 5, ’bleu’, 8, ’vert’, ’rouge’]
liste4=[liste1,liste2] #liste de listes
print(liste4) #affiche [[2, 5, ’bleu’, 8], [’vert’, ’rouge’]]
Attention, une liste composée d’un unique élément a s’écrit [a] sans virgule après le a contrairement
à la règle pour les n-uplets.
On peut utiliser la fonction range pour initialiser une liste d’entiers ou l’opérateur * pour la répétition :
liste1=list(range(4)) # [0,1,2,3]
liste2=list(range(3,6)) # [3,4,5]
liste3=list(range(3,11,2)) # [3,5,7,9]
liste4=3*liste2 # [3, 4, 5, 3, 4, 5, 3, 4, 5]
Construction par compréhension
C’est un procédé très utile de construction d’une liste. L’instruction est [expression(i) for i
in range()], par exemple :
Serge Bays
41
Lycée Les Eucalyptus
http://mathematice.fr
carre=[x**2 for x in range (1,10)] # construit [1,4,9,16,25,36,49,64,81]
Une liste est "itérable". Ainsi si on a défini une fonction f qui s’applique au type des éléments d’une
liste, on peut remplacer chaque élément de cette liste par son image avec le simple code suivant :
for x in maliste:
x=f(x)
Insertion et extraction
Pour ajouter un élément à la fin d’une liste, on utilise la méthode append :
liste=[’vert’,’rouge’]
liste.append(’jaune’) # on ajoute un élément à la fin de la liste
print(liste) #affiche [’vert’,’rouge’,’jaune’]
Pour insérer un objet dans une liste, on utilise la méthode insert ; pour extraire une sous-liste, on
opère comme pour le type str :
liste=[1,3,7,9]
liste.insert(2, 5) # on insère à l’index 2 l’élément 5
print(liste) #affiche [1,3,5,7,9], 7 et 9 sont décalés vers la droite
liste2=liste[1:4]
print(liste2) #affiche [3,5,7]
print(liste[-1]) #affiche 9, le dernier élément
Suppression d’un élément et tri
On utilise la méthode remove pour supprimer un élément et la méthode sort pour trier une liste :
liste=[1,3,7,9,3,5]
liste.remove(3) # on
print(liste) #affiche
liste.sort() #trie la
print(liste) #affiche
supprime l’élément 3 (seul le premier rencontré !)
[1,7,9,3,5], 7, 9, 3 et 5 sont décalés vers la gauche
liste
[1,3,5,7,9]
Référence
Un objet de type list peut être modifié. C’est très pratique lorsque c’est voulu mais aussi dangereux
par exemple avec le code suivant où on pourrait croire ne modifier que la liste "liste2" :
liste1=[1,3,5,7,9]
liste2=liste1
liste2.append(11)
print(liste1) #affiche [1,3,5,7,9,11]
Serge Bays
42
Lycée Les Eucalyptus
http://mathematice.fr
On peut penser que liste2 est une copie de liste1. Mais en fait liste1 et liste2 contiennent une référence
vers le même objet. Si l’objet est modifié avec l’une des deux variables, la modification se voit aussi avec
l’autre. Donc pour modifier une liste sans toucher à l’autre, il faut faire une véritable copie, c’est-à-dire
créer un nouvel objet. Le code est le suivant :
liste1=[1,3,5,7,9]
liste2=list(liste1) # liste2 est un nouvel objet
liste2.append(11) # seule liste2 est modifiée
print(liste1) #affiche [1,3,5,7,9]
6.2
Les tableaux et les matrices
Une liste peut être composée d’objets de différents types et en particulier de listes. Une liste composée
de n listes de longueurs p représente un tableau ou une matrice (n, p) (n lignes et p colonnes).
6.2.1
Création
On commence par créer une liste vide "matrice", puis avec une boucle for, on crée les listes "ligne"
une par une en les ajoutant à la liste "matrice" :
matrice=[]
for n in range(6): # 6 lignes
ligne=[ . . . ] # une ligne de longueur p
matrice.append(ligne)
6.2.2
Utilisation
La commande print(matrice[2]) permet par exemple d’afficher la troisième ligne. Puisque
"matrice[2]" est une liste, la commande print(matrice[2][4]) permet par exemple d’afficher le
cinquième élément de la troisième ligne. De manière générale la commande print(matrice[i][j])
permet d’afficher le (j+1)ème élément de la (i+1)ème ligne. Par exemple :
matrice=[]
for n in range(3): # 3 lignes
ligne=[j*j for j in range(3*n,3*(n+1)] # 3 colonnes
matrice.append(ligne)
print(matrice)
# affiche [[0, 1, 4], [9, 16, 25], [36, 49, 64]]
print(matrice[1])
# affiche [9, 16, 25]
print(matrice[1][2])
# affiche 25
6.2.3
Images
Une image est un tableau (n lignes et p colonnes) de pixels (picture elements) et chaque pixel, dans le
système RVB, est constitué de trois couleurs (rouge, vert, bleu). Dans un fichier au format bmp les pixels
sont écrits les uns à la suite des autres ; chaque couleur est codée par un nombre de 0 à 255 codé par un
octet et il faut donc trois octets pour coder un pixel. Afin d’écrire ou de lire un tel ficher on peut donc
utiliser une liste de n listes de longueurs p si on s’intéresse à chaque pixel, ou bien une liste de n listes de
longueur 3 × p si on s’intéresse à chacun des trois octets formant un pixel.
Serge Bays
43
Lycée Les Eucalyptus
http://mathematice.fr
Attention : il peut y avoir un problème au niveau de la mémoire qui ne peut stocker des listes trop
grandes. La taille maximale est de l’ordre de quelques centaines de millions. Il est possible de faire un test,
par exemple avec l’instruction liste=[0]*n, pour déterminer la valeur maximale de n.
Serge Bays
44
Lycée Les Eucalyptus
Chapitre 7
Les fichiers
7.1
Gestion des fichiers
Un programme s’exécute dans la mémoire volatile (RAM) de l’ordinateur. Pour conserver une trace,
il faut utiliser une mémoire permanente comme un disque ou une clé où les données sont organisées en
fichiers par le système d’exploitation.
Si on travaille avec l’interpréteur, il est nécessaire de déterminer le répertoire de travail. Par défaut
c’est le répertoire où est installé Python (par exemple "Python33"). On peut changer ce répertoire de travail
avec la fonction chdir (change directory) du module os, par exemple :
from os import chdir
chdir(’C:/Users/Toto/Info/tp7’)
Le répertoire "tp7" est maintenant le répertoire où seront créés les fichiers. Attention, ce répertoire doit
préalablement exister. Si on travaille avec un fichier ".py", le répertoire courant est celui où est enregistré
le fichier ".py".
7.1.1
Ouverture d’un fichier
Il y a trois manières d’ouvrir un fichier en mode texte : on utilise la fonction open qui prend comme
premier paramètre le nom du fichier et en second paramètre ’w’ pour le mode "écriture", ’r’ pour le mode
"lecture" et ’a’ pour le mode "ajout".
– En mode écriture, le fichier est créé dans le répertoire courant du programme ou écrasé s’il existe
déjà puis ouvert en écriture.
– En mode ajout le fichier doit déjà exister, il est ouvert en écriture et toutes les données écrites sont
automatiquement ajoutées à la fin du fichier.
– En mode lecture le fichier doit déjà exister et est ouvert en lecture.
La syntaxe est :
fic1=open(’fichier1’,’w’)
fic2=open(’fichier2’,’r’)
fic3=open(’fichier3’,’a’)
45
http://mathematice.fr
7.1.2
Fermeture d’un fichier
Pour fermer un fichier, il y a une seule instruction :
fic1.close()
A la fin de l’utilisation, il est impératif de fermer le fichier, sinon son contenu ne peut pas être garanti.
7.2
Ecriture et lecture
7.2.1
Ecriture
Par défaut, Python utilise les fichiers en mode texte et on y écrit des chaînes de caractères (type str)
en utilisant la méthode write. Voici un premier exemple :
fic=open(’fichier1.txt’,’w’)
fic.write(’Bonjour, comment allez-vous ?’)
fic.close()
Ce code crée un fichier "fichier1.txt" dans le répertoire courant. Ce fichier contient sur une ligne la
phrase : Bonjour, comment allez-vous ?
Si ou souhaite écrire sur plusieurs lignes, on utilise le caractère ’\n’ pour un retour à la ligne.
Le code est :
fic=open(’fichier1.txt’,’w’)
fic.write(’Bonjour,’+’\n’+ ’comment allez-vous ?’)
fic.close()
Le fichier contient alors les deux lignes :
Bonjour,
comment allez-vous ?
Attention le code qui suit ne fonctionne pas pour écrire la phrase sur deux lignes :
fic=open(’fichier1.txt’,’w’)
fic.write(’Bonjour,’)
fic.write(’comment allez-vous ?’)
fic.close()
On obtient la phrase sur une seule ligne sans espace après "Bonjour,".
Si on relance le même programme, le fichier qui existe déjà va être écrasé et réécrit.
Si on ne souhaite pas l’écraser et écrire à la suite dans ce fichier, on le rouvre avec l’instruction
fic=open(’fichier1.txt’,’a’).
Le code qui suit ajoute une nouvelle ligne à la fin du fichier texte :
Serge Bays
46
Lycée Les Eucalyptus
http://mathematice.fr
fic=open(’fichier1.txt’,’a’)
fic.write(’\n’+’Au revoir’)
fic.close()
Pour écrire des données numériques de type int ou float, il suffit de les convertir préalablement en
type str.
Par exemple si on souhaite écrire un tableau de valeurs pour une fonction, on convertit les nombres
de type float en chaîne de caractères de type str et on utilise la méthode write :
def f(x):
return x*(1-x)
fic=open(’fichier2.dat’,’w’)
for i in range(101):
x=i/100
y=f(x)
fic.write(str(x)+’\t’+str(y)+’\n’)
# ’\t’ pour une tabulation et ’\n’ pour un retour à la ligne
fic.close()
Ensuite on ouvre un logiciel comme Gnuplot où on écrit les instructions :
set title "y=x(1-x)"
plot ’C :\Users\Toto\Info\tp7\fichier1.dat’ w l
Gnuplot lit alors le fichier texte de données et trace la courbe correspondante.
7.2.2
Lecture
Pour lire dans un fichier texte, on ouvre le fichier en lecture et on utilise la méthode read. Il ne faut
pas oublier de fermer le fichier après la lecture. (fic.read(n) lit n caractères, fic.read() lit tout le fichier).
Serge Bays
47
Lycée Les Eucalyptus
http://mathematice.fr
fic=open(’fichier1.txt’,’r’)
monfichier=fic.read() # monfichier est de type str
print(monfichier) # ou print(fic.read()) lit et affiche tout le fichier
fic.close()
L’objet "fic" est un ensemble de lignes, chacune étant une chaîne de caractères. On peut récupérer une
ligne dans une variable de type str avec le code suivant :
fic=open(’fichier1.txt’,’r’)
ligne=fic.readline() # lit la ligne courante et passe à la suivante
fic.close()
On peut aussi récupérer toutes les lignes dans une liste. Chaque élément de la liste est alors une chaîne
de caractères. Chaque chaîne est une ligne du fichier.
fic=open(’fichier1.txt’,’r’)
lignes=fic.readlines() #liste de lignes
print(len(lignes)) # affiche le nombre de lignes
print(lignes[0]) # affiche la première ligne
fic.close()
On peut décomposer chaque ligne qui est une chaîne de caractères en mots. La méthode rstrip()
supprime le caractère ’\n’ de retour à la ligne et la méthode split() découpe la ligne et la transforme en une
liste de mots lorsque ces mots sont séparés par des espaces ou n’importe quel caractère.
Pour ce code, on a créé un fichier ’lecture.txt’ qui contient la chaîne "bonjour tout le monde 25 53.4".
fic=open(’lecture.txt’,’r’)
chaine=fic.read()
print(chaine.split())
fic.close()
Ce code affiche : [’bonjour’, ’tout’, ’le’, ’monde’, ’25’, ’53.4’]. On a créé une liste de mots à partir
d’une chaîne.
Si les données à récupérer sont de type numérique, il suffit alors de convertir chaque mot en int ou
en float. Avec le fichier de donnés "fichier2.dat’, créé plus haut, qui contient des lignes de deux flottants
séparés par une tabulation (’\t’), le code est :
fic=open(’fichier2.dat’,’r’)
for ligne in fic:
coord=ligne.rstrip().split(’\t’) # coord est une liste de 2 mots
x,y=float(coord[0]),float(coord[1])
Serge Bays
48
Lycée Les Eucalyptus
http://mathematice.fr
7.3
Fichiers binaires
Un fichier est une suite de 0 et de 1 que l’on regroupe par octet. Par exemple l’octet qui vaut 41 en
hexadécimal peut représenter le nombre entier 65 qui indiquera la quantité de rouge pour un pixel donné
dans une image ou bien le code ASCII du caractère ’A’ s’il s’agit d’un fichier texte.
C’est le format du fichier qui indique comment il va être interprété.
Les méthodes write(n) et read(n) permettent d’écrire ou de lire n octets en mode binaire. Les objets
lus ou écrits sont du type bytes (tableau d’octets).
f = open("nom1", "rb") # b utilisé pour ouvrir le fichier en mode binaire
g = open("nom2", "wb")
octets=f.read(3) # lit 3 octets (octets est du type bytes)
g.write(octets) # écrit les 3 octets
# ou g.write(b’\x00\x41\x80\xff’) écrit 4 octets
# ou g.write(b’\x00A\x80\xff’) écrit les 4 mêmes octets
# ou g.write(bytes([0,65,128,255])) écrit les 4 mêmes octets
f.close()
g.close()
Serge Bays
49
Lycée Les Eucalyptus
Chapitre 8
Algorithmes : validité et complexité
8.1
Validité d’un algorithme itératif
Un algorithme itératif est contruit avec des boucles, par opposition à récursif qui remplace les boucles
par des appels à lui-même.
8.1.1
Invariants de boucle
Le principe
La méthode des "invariants de boucle" aide à prouver la validité d’un algorithme itératif.
Définition
Un invariant d’une boucle est une propriété qui est vérifiée à chaque exécution du corps de cette
boucle. On utilise un raisonnement par récurrence pour prouver qu’une propriété est un invariant d’une
boucle :
• initialisation : on montre que la propriété est vérifiée avant le premier passage dans le corps de la
boucle,
• hérédité : on montre que si l’invariant est vérifié avant une exécution quelconque du corps de la
boucle, il est encore vérifié avant l’exécution suivante.
• conclusion : l’invariant est alors vérifié à la fin de la boucle, ce qui traduit le fait que la boucle
réalise bien la tâche souhaitée.
Exemple
On effectue la division euclidienne de a par b où a et b sont deux entiers strictement positifs. Il s’agit
donc de déterminer deux entiers q et r tels que a = bq +r avec 0 ≤ r < b. Voici un algorithme déterminant
q et r :
q=0
r=a
tant que r ≥ b
q =q+1
r =r−b
fin du tant que
On choisit comme invariant de boucle la propriété a = bq + r.
– Initialisation : q est initialisé à 0 et r à a, donc la propriété a = bq + r = b.0 + a est vérifiée avant
le premier passage dans la boucle.
– Hérédité : avant une itération arbitraire, supposons que l’on ait a = bq + r et montrons que cette
propriété est encore vraie après cette itération. Soient q 0 la valeur de q à la fin de l’itération et r0
la valeur de r à la fin de l’itération. Nous devons montrer que a = bq 0 + r0 . On a q 0 = q + 1 et
r0 = r − b, alors bq 0 + r0 = b(q + 1) + (r − b) = bq + r = a. La propriété est bien conservée.
50
http://mathematice.fr
8.1.2
Terminaison
Le principe
L’algorithme étudié ci-dessus semble valide, mais rien ne prouve pour l’instant que le programme se
termine, et que lorsqu’il s’arrête, on aura bien 0 ≤ r < b.
Pour prouver qu’un programme s’arrête, on vérifie que la suite formée par les valeurs des variables au
cours des itérations converge en un nombre fini d’étapes vers une valeur satisfaisant la condition d’arrêt.
Exemple
Nous reprenons l’exemple précédent.
– Commençons par montrer que le programme s’arrête : la suite formée par les valeurs de r au cours
des itérations est une suite d’entiers strictement décroissante : r étant initialisé à a, si a ≥ b alors
la valeur de r sera strictement inférieure à celle de b en un maximum de a − b étapes.
– Maintenant, si le programme s’arrête, c’est que la condition du "tant que" n’est plus satisfaite, donc
que r < b. Il reste à montrer que r ≥ 0. Comme r est diminué de b à chaque itération, si r < 0,
alors à l’itération précédente la valeur de r était r0 = r + b ; or r0 < b puisque r < 0. Et donc la
boucle se serait arrêtée à l’itération précédente, ce qui est absurde ; on on déduit que r ≥ 0.
En conclusion, le programme se termine avec 0 ≤ r < b et la propriété a = bq + r est vérifiée à chaque
itération ; ceci prouve que l’algorithme effectue bien la division euclidienne de a par b.
8.1.3
Un autre exemple
L’objectif est de calculer le produit de deux nombres entiers positifs a et b sans utiliser de multiplication :
p=0
m=0
tant que m < a
m=m+1
p=p+b
fin du tant que
Comme dans l’exemple précédent, le programme se termine car la suite des m est une suite d’entiers
consécutifs strictement croissante, et atteint la valeur a en a étapes.
Un invariant de boucle est ici : p = m.b
– Intialisation : avant le premier passage dans la boucle, p = 0 et m = 0, donc p = m.b.
– Hérédité : supposons que p = m.b avant une itération ; les valeurs de p et m après l’itération sont
p0 = p + b et m0 = m + 1. Or p0 = (p + b) = m.b + b = (m + 1)b = m0 b. Donc la propriété reste
vraie.
– Conclusion : à la sortie de la boucle p = m.b.
Puisqu’à la sortie de la boucle m = a, on a bien p = a.b.
8.2
Complexité
Pour traiter un même problème, il existe souvent plusieurs algorithmes et un algorithme n’aura pas
le même temps d’exécution s’il est programmé dans deux langages différents ou s’il est exécuté sur deux
machines différentes. Pour pouvoir comparer deux algorithmes il faut donc trouver un moyen de mesurer
le temps d’exécution indépendamment du langage et de la machine.
En général, le temps d’exécution d’un algorithme sera évalué en fonction de la taille des données.
Par exemple, le temps d’exécution d’une recherche dans un tableau dépend de la taille de ce tableau. Cette
évaluation peut se révèler parfois très difficile, mais dans de nombreux cas, elle peut se faire en appliquant
quelques règles simples.
Serge Bays
51
Lycée Les Eucalyptus
http://mathematice.fr
8.2.1
Mesure du temps d’exécution
La quantité de données prise en entrée sera notée n ; par exemple la taille d’un tableau, le nombre de
caractères d’une chaîne, etc.
La procédure est la suivante :
– nous comptons le nombre d’opérations un exécutées par l’algorithme sans nous intéresser au temps
mis par une machine particulière à exécuter une opération.
– nous étudions la croissance du nombre d’opérations un effectuées par l’algorithme en fonction du
nombre n de données.
Les règles pour évaluer le temps d’exécution sont alors les suivantes :
• le temps d’exécution, relativement petit, d’une affectation, d’une comparaison ou d’une opération
simple constitue l’unité de base.
• Le temps pris pour effectuer une séquence "[p q]" est la somme des temps pris pour exécuter
les instructions "p" puis "q".
• le temps pris pour exécuter un test "if (b) : p else : q" est inférieur ou égal au maximum des
temps pris pour exécuter les instructions "p" et "q", plus une unité pour évaluer l’expression "b".
• le temps pris pour exécuter une boucle "for i variant de 1 à m : p" est m fois le temps pris pour
exécuter l’instruction "p". Si le nombre m ne dépend pas des entrées de l’algorithme, alors le temps pris
pour exécuter cette boucle est une constante.
• le cas des boucles "while" est plus complexe à traiter puisqu’en général le nombre de répétitions
n’est pas connu a priori.
Pour une même quantité de données, le temps d’exécution peut être très variable : lorsqu’on recherche
un élément dans un tableau, l’élément peut se trouver au début du tableau dans le cas le plus favorable ou
à la fin du tableau dans le pire des cas. Le plus souvent nous considérerons le pire des cas.
8.2.2
Borne asymptotique supérieure
Une suite u est de borne asymptotique supérieure v si pour n assez grand, u est majorée par v à une
constante près. On écrira un ∈ O(vn ).
Définition : un ∈ O(vn ) si ∃N ∈ N, ∃k ∈ R, ∀n > N , un ≤ kvn .
En pratique, on utilise la propriété suivante :
un
Propriété : un ∈ O(vn ) si lim
= ` (autrement dit, si
n→+∞ vn
8.2.3
un
vn
( u est majorée par k.v)
converge vers une constante).
Niveaux de complexité
Complexité constante
Un algorithme est en temps constant, O(1), si son temps d’exécution est indépendant du nombre de
données ; par exemple, retourner le premier élément d’une liste ne dépend pas de la longueur de la liste.
Complexité logarithmique
Un algorithme de complexité logarithmique, O(ln n), croît de façon linéaire en fonction de 2n ; cela
signifie que pour doubler le temps d’exécution, il faut mettre au carré le nombre de données. La recherche
par dichotomie dans un tableau trié est de complexité O(ln n).
Pour la plupart, ces algorithmes sont dans la pratique très performants.
Serge Bays
52
Lycée Les Eucalyptus
http://mathematice.fr
Complexité linéaire
Un algorithme est de complexité linéaire, O(n), si le temps de calcul croît de façon linéaire en fonction du nombre de données. La recherche séquentielle dans un tableau non trié est de complexité linéaire :
dans le pire des cas, l’élément que l’on recherche est celui qui est examiné en dernier et il est donc nécessaire d’effectuer n itérations (qui s’effectuent en temps constant) pour examiner chaque élément du
tableau. (Autres exemples : le calcul d’une somme ou d’une moyenne.)
Complexité log-linéaire
Certains algorithmes de tri sont de complexité O(n. ln n). C’est le meilleur résultat qu’il est possible
d’obtenir avec des tris de comparaisons.
Complexité quadratique
D’autres algorithmes de tri, construits avec deux boucles imbriquées, effectuent un nombre d’itérations de l’ordre de n2 . Souvent, les problèmes pour lesquels il existe des algorithmes quadratiques, O(n2 ),
admettent aussi des algorithmes de meilleure complexité.
Complexité polynomiale
Ce sont les algorithmes, en O(nk ), k fixé, dont le temps d’exécution peut être majoré par un polynôme. On utilise le terme polynomial par opposition à exponentiel. En algorithmique, il est très important
de faire la différence entre les algorithmes polynomiaux, utilisables en pratique, et les algorithmes exponentiels, inutilisables en pratique.
Complexité exponentielle
Ces algorithmes en O(k n ), k > 1, sont tellement longs à l’exécution, qu’on ne les utilise presque
jamais. Malheureusement, il existe des problèmes pour lesquels les seuls algorithmes de résolution exacte
connus à l’heure actuelle sont de complexité exponentielle.
8.3
8.3.1
Exemples
Recherche séquentielle dans un tableau non trié
Le programme suivant effectue la recherche d’un élément dans un tableau t de taille n par balayage
(en anglais, linear search). Le programme s’arrête dès que l’élément est trouvé ou lorsque le compteur i
atteind la valeur n. Dans le pire des cas, on parcourt donc tout le tableau et la complexité est en O(n).
Pour le tableau t, on peut utiliser les types list, tuple ou même le type str.
def recherche(x, t):
n = len(t)
i = 0
while (i < n) and (x != t[i]):
i = i + 1
if i < n:
return i
else:
return False
En utilisant une boucle "for", on peut écrire un programme plus condensé (ci-dessous) mais la complexité est toujours en O(n).
Serge Bays
53
Lycée Les Eucalyptus
http://mathematice.fr
def search(x, t):
for i in range(len(t)):
if t[i]==x:
return i
return False
8.3.2
Recherche par dichotomie dans un tableau trié
Si le tableau est trié on peut utiliser le principe de dichotomie (binary search en anglais). A chaque
étape, on coupe le tableau en deux et on effectue un test pour savoir dans quelle partie peut se trouver
l’élément cherché. C’est le principe diviser pour régner (en anglais divide-and-conquer). On utilise ici le
type list pour pouvoir préalablement trier le tableau avec la méthode sort().
def rechercheDichotomie(x,liste):
g = 0
d = len(liste)
while g < d-1:
k = (g+d) // 2
if x < liste[k]:
d = k
else:
g = k
if x == liste[g]:
return g
else:
return False
Après k itérations, si n est la taille du tableau, d − g ≤
n
(démonstration par récurrence).
2k
n
ln n
≤
1
dès
que
k
≥
et dans ce cas le programme s’arrête. La complexité de la recherche
ln 2
2k
dichotomique est donc O(ln n).
Or
8.3.3
Recherche d’un mot dans une chaîne de caractères
Le principe est le même que pour la recherche d’un caractère dans une chaîne mais ici il nécessaire
d’ajouter une boucle "while" pour tester tous les caractères du mot.
def searchWord(mot,texte):
if len(mot)>len(texte):
return False
for i in range(1+len(texte)-len(mot)):
j=0
while j<len(mot) and mot[j]==texte[i+j]:
j+=1
if j==len(mot):
return i
return None
Dans le pire des cas le programme va chercher le mot à toutes les places possibles et va tester tous les
caractères du mot. La complexité est donc de l’ordre de m(1 + n − m) où m est la longueur du mot et n
la longueur du texte.
Serge Bays
54
Lycée Les Eucalyptus
http://mathematice.fr
En particulier le maximum est atteint pour m =
n
et on obtient alors une complexité de l’ordre de
2
n2 + 2n
; dans ce cas la complexité de l’algorithme est donc en O(n2 ).
4
Serge Bays
55
Lycée Les Eucalyptus
Chapitre 9
Résolution d’une équation : méthodes de
dichotomie et de Newton
9.1
Recherche dichotomique
L’algorithme de recherche dichotomique ("bisection search" en anglais) a déjà été étudié. A partir
de deux valeurs a et b encadrant une solution unique d’une équation f (x) = 0, on teste si la solution est
plus grande ou plus petite que m = (a + b)/2 et suivant le résultat, on restreint la recherche à l’intervalle
[a; m] ou à l’intervalle [m; b]. On reproduit ce schéma tant que l’amplitude de l’intervalle (qui est divisée
par deux à chaque étape) est supérieure à une précision epsilon donnée.
Algorithme :
Variables et Initialisation
a et b, les bornes de l’intervalle [a ; b]
f, la fonction (f change de signe entre a et b)
epsilon la précision
Traitement
Tant que b - a > epsilon
m prend la valeur (a+b)/2
Si f(m) et f(a) sont de même signe alors
a prend la valeur m
sinon
b prend la valeur m
Sortie
a et b (pour un encadrement) ou (a+b)/2 (valeur approchée)
Une programmation possible en Python :
def zeroDic(f,a,b,eps):
while b-a > eps:
m = (a+b)/2
if f(a) * f(m) > 0:
a = m
else:
b = m
return (a+b)/2
56
http://mathematice.fr
L’amplitude de l’intervalle étant divisé par deux à chaque étape, on gagne un bit de précision à chaque
passage dans la boucle "while". L’intérêt de cette méthode est que les conditions sur la fonction f ne sont
pas trop exigeantes : être continue et changer de signe.
Analyse de l’algorithme :
Il est nécessaire de démontrer la terminaison et la validité de cet algorithme.
b−a
Pour la terminaison, il suffit de remarquer qu’après k étapes, b − a a été divisé par 2k et comme k
2
a pour limte 0 quand k tend vers l’infini, pour tout > 0, il existe une valeur de k à partir de laquelle toutes
les amplitudes des intervalles seront inférieures à .
Pour la validité, on utilise l’invariant f (a)f (b) ≤ 0. Cet invariant est bien vérifié avant l’entrée dans
la boucle par hypothèse. Ensuite on suppose que cet invariant est vérifié avant un passage dans la boucle :
si f (a) et f (m) sont de même signe, alors a prend la valeur de m et donc garde un signe contraire à celui
de b ; si f (a) et f (m) sont de signe contraire, alors b prend la valeur de m et donc garde un signe contraire
à celui de a.
Ainsi les valeurs de a et b en sortie sont les bornes d’un intervalle d’amplitude maximale telles que
f (a)f (b) ≤ 0. D’après le théorème des valeurs intermédiaires, la solution appartient à cet intervalle.
Pour la complexité, si on ne tient pas compte de la complexité des calculs de f (m) lors des appels
b−a
b−a
à la fonction, on remarque que la boucle est exécutée k fois si et seulement si
≤ < k−1 , soit
k
2 !
2
!
b−a
b
−
a
b
−
a
b
−
a
≤ 2k < 2
. On obtient alors ln
≤ k ln 2 < ln 2 + ln
ce qui nous donne
!
!
b−a
b−a
≤ k < 1 + log2
. Par exemple si b − a = 1 et = 2−p alors k = p.
log2
9.2
Méthode de Newton
9.2.1
Principe
On cherche la solution de l’équation f (x) = 0, c’est-à-dire l’abscisse du point d’intersection de la
courbe C représentant f avec l’axe des abscisses. Sous certaines conditions sur f , on part d’une valeur x0
et on détermine l’abscisse x1 du point d’intersection de la tangente T1 à la courbe C au point d’abscisse x0
f (x0 )
avec l’axe des abscisses ; x1 est solution de l’équation : f 0 (x0 )(x−x0 )+f (x0 ) = 0. Donc x1 = x0 − 0
f (x0 )
et x1 est une valeur approchée de x. On recommence un certain nombre de fois avec xn et la tangente Tn
f (xn−1 )
au point d’abscisse xn−1 . Soit xn = xn−1 − 0
; la suite (xn ) converge vers la solution x.
f (xn−1 )
9.2.2
Exemples
Calcul de l’inverse
On détermine la solution x =
1
1
1
de l’équation − a = 0. On a f 0 (x) = − 2 et :
a
x
x
xn = xn−1 −
Serge Bays
57
f (xn−1 )
f 0 (xn−1 )
Lycée Les Eucalyptus
http://mathematice.fr
1
xn = xn−1 −
xn = xn−1 +
−a
xn−1
−1
x2n−1
!
1
− a x2n−1
xn−1
xn = xn−1 + xn−1 − ax2n−1
xn = xn−1 (2 − axn−1 )
Calcul de la racine carrée
On détermine la solution de l’équation x2 − a = 0. On a f (x) = x2 − a et f 0 (x) = 2x.
xn = xn−1 −
f (xn−1 )
f 0 (xn−1 )
xn = xn−1 −
x2n−1 − a
2xn−1
xn =
x2n−1 + a
2xn−1
1
a
xn =
xn−1 +
2
xn−1
!
Programme en Python :
def racine(a,x,eps):
while abs(x*x-a) > eps:
x=0.5*(x+a/x)
return x
On peut compléter le code précédent afin de compter le nombre d’itérations et comparer l’efficacité
de cet algorithme avec celle de la recherche dichotomique. Avec la recherche dichotomique, pour une
précision de 10−4 , si l’intervalle de départ a une amplitude de 1, il est nécessaire de le diviser en deux n
fois avec 2n ≥ 104 , soit n ≥ 4 ln 10/ ln 2 ce qui nous donne n = 14. Avec la méthode de Newton, trois
itérations sont suffisantes. Le nombre de décimales correctes est multiplié par deux à chaque étape.
def racine(a,x,eps):
cpt=0
while abs(x*x-a) > eps:
x=0.5*(x+a/x)
cpt+=1
return x,cpt
Serge Bays
58
Lycée Les Eucalyptus
http://mathematice.fr
9.2.3
Cas général
f (xn−1 )
il est nécessaire de
f 0 (xn−1 )
définir dans le programme la fonction f et la fonction f 0 , que l’on notera "dfdx". La variable "cpt" est
un compteur permettant d’afficher le nombre d’itérations nécessaires pour obtenir la précision souhaitée.
Mais nous ne connaissons pas à l’avance le nombre d’itérations et il y a des cas où la suite diverge, donc il
est important de limiter ce nombre ; c’est le rôle de l’argument N dans le programme qui suit.
Afin de calculer les termes de la suite (xn ) définis par xn = xn−1 −
def newton(f,x,dfdx,eps,N=100):
cpt=0
while abs(f(x)) > eps and cpt<=N:
x=x-f(x)/dfdx(x)
cpt+=1
return x, cpt, f(x)
On peut améliorer ce code de plusieurs manières.
– Dans la boucle, on évalue deux fois la quantité f (x). Sur de petits exemples cela n’a pas une
grande importance, mais dans le cas de fonctions beaucoup plus compliquées, faire deux fois le
même travail peut ne pas être négligeable. Nous pouvons donc stocker la valeur f (x) dans une
variable locale.
– Un problème sérieux est le risque de diviser par zéro ou par un nombre très petit qui pourrait créer
une très grande valeur pour x et faire diverger la méthode. C’est pourquoi nous devons tester les
valeurs de f 0 (x) et afficher un avertissement si une valeur devient très petite.
– Il est aussi intéressant de stocker dans une liste les valeurs x et f (x) obtenues à chaque itération
pour les imprimer ou les utiliser dans un graphique illustrant le comportement de la méthode de
Newton. Pour cela nous pouvons ajouter en argument un booléen indiquant si nous stockons ou pas
ces valeurs.
Voici un code optimisé :
def newton(f,x,dfdx,eps,N=100,save=False):
valeur_f=f(x)
cpt=0
if save: valeurs=[(x,valeur_f)]
while abs(valeur_f) > eps and cpt<=N:
valeur_dfdx=dfdx(x)
if abs(valeur_dfdx)<1E-14:
print("Attention, valeur de f’ trop petite")
break
x=x-valeur_f/valeur_dfdx
cpt+=1
valeur_f=f(x)
if save: valeurs.append((x,valeur_f))
if save:
return x,valeurs
else:
return x, cpt, valeur_f
Serge Bays
59
Lycée Les Eucalyptus
http://mathematice.fr
9.3
Complément
9.3.1
Méthode de la sécante
Le calcul de f 0 (x) peut être compliqué et si nous devons résoudre plusieurs équations, il peut être intéressant de faire effectuer ce calcul par le programme. Pour cela nous pouvons utiliser une approximation
f (x + h) − f (x − h)
avec h de l’ordre de 10−6 par exemple.
en remplaçant f 0 (x) par
2h
La méthode s’appelle alors la "méthode de la sécante".
def DfDx(f,x):
h=1e-6
return (f(x+h)-f(x-h))/(2*h)
On remplace alors "dfdx" par "DfDx" dans le code de la fonction "newton"
9.3.2
Optimisation avec eval et exec
Plutôt que modifier la fonction f dans le code du programme, on peut faire en sorte que le programme
demande à l’utilisateur d’entrer l’expression de la fonction au clavier. On importe au préalable toutes les
fonctions du module math (sin, cos, exp, . . . ). Puis on utilise les fonctions eval et exec.
Le code suivant doit alors se trouver au début du programme.
from math import *
formule=input("entrer l’expression de la fonction")
code="""
def f(x):
return eval(formule)
"""
exec(code)
D’une certaine manière, l’instruction exec(code) remplace la partie "code= """ . . . """ par les
instructions se trouvant entre les guillemets. La fonction eval évalue le contenu de la chaîne "formule".
(Par exemple eval(’2+3’) renvoie 5).
9.4
Utilisation de la bibliothèque scipy
Le module optimize de la bibliothèque scientifique scipy contient les fonctions bisect et newton dans
lesquelles sont programmées respectivement la méthode de dichotomie et la méthode de Newton.
Les fonctions root et fsolve permettent également de trouver les valeurs approchées des zéros d’une
fonction.
import scipy.optimize
def f(x):
return x**2-2
a=1
b=2
Serge Bays
60
Lycée Les Eucalyptus
http://mathematice.fr
x=scipy.optimize.bisect(f,a,b)
print("sol=",x)
x=scipy.optimize.newton(f,a)
print("sol=",x)
x=scipy.optimize.fsolve(f,a)
print("sol=",x)
x=scipy.optimize.root(f,a)
print("sol=",x)
Serge Bays
61
Lycée Les Eucalyptus
Chapitre 10
Résolution numérique d’équations
différentielles : méthode d’Euler
Les équations différentielles permettent de modéliser de nombreux phénomènes physiques. En général, on ne dispose pas de solutions analytiques : par exemple, l’équation θ00 = −k1 sin θ − k2 θ0 permet
d’étudier le mouvement d’un pendule amorti et il donc est intéressant de pouvoir visualiser une approximation de la solution.
10.1
Méthode d’Euler
S’il existe une unique solution y, sur un intervalle [a; b], de l’équation y 0 (x) = f (x, y(x)) avec y(a)
fixé, il s’agit d’approcher y en un certain nombre de points répartis dans cet intervalle. En particulier, si
n + 1 points sont répartis régulièrement sur [a; b], on définit le pas h = b−a
n , soit xk = a + kh pour
k = 0, 1, 2, . . . , n. L’objectif est de calculer des approximations yk des valeurs y(xk ).
On utilise l’approximation
y(x + h) − y(x)
' y 0 (x) appliquée pour chaque xk , et on obtient
h
y(xk+1 ) − y(xk ) ' hy 0 (xk ) = hf (xk , y(xk )) ' hf (xk , yk )
Schéma : on calcule les approximations pour k = 0, 1, 2, . . . , n − 1 par :
xk+1 = xk + h et yk+1 = yk + hf (xk , yk )
On initialise avec y0 = y(x0 ) = y(a) (qui est la seule valeur exacte).
Une programmation de ce schéma consiste à construire deux listes, une pour la suite (xk ) des abscisses et une pour la suite (yk ) des ordonnées. On définit une fonction euler(a,b,y0,h,f) qui prend en
argument les valeurs extrêmes de l’intervalle a et b, la valeur initiale y(0), le pas h, la fonction f et renvoie
les listes des abscisses et des ordonnées.
def euler(a,b,y0,h,f):
y = y0
x = a
liste_y = [y0] # la liste des valeurs renvoyées
liste_x = [a]
while x+h <= b:
y += h * f(x, y)
liste_y.append(y)
62
http://mathematice.fr
x += h
liste_x.append(x)
return liste_x, liste_y
10.2
Exemples
10.2.1
Exemple 1
On cherche une solution approchée de l’équation différentielle y 0 = −2x + 1, avec y(0) = 2, sur
l’intervalle [0; 4]. La solution exacte est y(x) = −x2 + x + 2.
Avec la méthode d’Euler, on calcule yk+1 = yk + hf (xk , yk ).
On obtient la figure suivante avec un pas h = 0.5 :
10.2.2
Exemple 2
On cherche une solution approchée de l’équation y 0 = y, avec y(0) = 1, sur l’intervalle [0; 5]. La
solution exacte est y(x) = ex . Avec la méthode d’Euler, on calcule yk+1 = yk +hyk , soit yk+1 = (1+h)yk .
Avec y0 = 1, on obtient yk+1 = (1 + h)k+1 .
La figure suivante est réalisée avec différentes valeurs du pas h.
Avec la méthode d’Euler, l’erreur a deux causes constatées sur les exemples précédents : des erreurs
d’arrondi dans les opérations effectuées par l’ordinateur et une erreur de discrétisation, (ek = yk − y(xk )),
due au procédé de calcul.
Il est important que l’erreur de discrétisation diminue lorsque le pas h diminue. On dit que la méthode
converge si, pour tout k, yk tend vers y(xk ) quand h tend vers 0. Dans ce cas il faudra comme souvent faire
un compromis entre la précision de l’approximation et le temps de calcul.
Serge Bays
63
Lycée Les Eucalyptus
http://mathematice.fr
10.2.3
Exemple 3
Problème de stabilité : on résout l’équation y 0 = −y avec y(0) = 1 sur l’intervalle [0; 30]. La solution
exacte est y(x) = e−x . Ici l’intervalle est "grand" et si le pas n’est pas assez petit, on a un problème de
stabilité.
Instabilité pour h = 2, 5 :
Stabilité pour h = 1, 5 :
10.3
Complément
On peut résoudre une équation différentielle de degré 2 ou plus en vectorialisant l’équation.
Serge Bays
64
Lycée Les Eucalyptus
http://mathematice.fr
L’équation y 00 + y = 0 est équivalente à (y, y 0 )0 = (y 0 , −y) = F (y, y 0 ), soit en posant Y = (y, y 0 ),
on obtient l’équation Y 0 = F (Y ).
La méthode d’Euler peut s’appliquer ici et pour la programmation, Y sera un objet de type tuple
ou list. Mais les calculs se compliquent car par exemple : (3,4)+(2,5)=(3,4,2,5) (concaténation des deux
couples) et non pas (5,9) comme on le souhaiterait. Il faudra donc en particulier détailler le calcul de
Y + hF (Y ) dans la définition de la fonction euler.
On commence par modifier la définition de la fonction f :
def f(x,y): # y est un couple
return (y[1],-y[0])
Puis la définition de la fonction euler :
def euler(a,b,y0,h,f):
x=a
y=y0
liste_x=[a]
liste_y=[y0]
while x+h<=b:
y=(y[0]+h*(f(x,y)[0]),y[1]+h*(f(x,y)[1])) # la difficulté
liste_y.append(y)
x+=h
liste_x.append(x)
return liste_x,liste_y
Il est aussi possible et plus simple d’utiliser un objet de type array, (tableau en français).
Un objet de type array ressemble à un objet de type list, mais ici, tous les éléments doivent être du
même type et le nombre d’éléments doit être connu à la création. Les objets de type array se trouvent dans
une bibliothèque appelée "Numerical Python" (NumPy) élaborée pour un calcul numérique optimisé.
Il est alors plus simple de calculer avec des tableaux car les opérations mathématiques sont prédéfinies.
Serge Bays
65
Lycée Les Eucalyptus
http://mathematice.fr
Exemples d’utilisation :
import numpy as np
a=np.array([3,4]) # convertit une liste en tableau
b=np.array([2,5])
print(a+b) # affiche [5 9]
print(3*a) # affiche [9 12]
print((a+b)[0]) # affiche 5
Maintenant, il n’est plus nécessaire de modifier la définition de la fonction euler.
def euler(a,b,y0,h,f):
x=a
y=y0
liste_x=[a]
liste_y=[y0]
while x+h<=b:
y=y+h*f(x,y)
# plus aucun problème de calcul
liste_y.append(y)
x+=h
liste_x.append(x)
return (liste_x,liste_y)
Il faut cependant modifier la définition de la fonction f qui renvoie un objet de type array et l’appel
de la fonction euler :
def f(x,y):
return array((y[1],-y[0])) # y est un array (F(a,b)=(b,-a))
x,y=euler(a,b,array((0,1)),eps,f) #initialisation y(0)=0 et y’(0)=1
Utilisation de la bibliothèque Scipy.
Pour une équation du type x0 (t) = f (x(t), t), on utilise la fonction odeint de scipy.integrate.
from math import cos, sin, pi
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as integ
def f(x,t):
return 2*(cos(t*x))*x*(1-x/2)
t=np.linspace(0,15,num=300)
sol=integ.odeint(f,4,t)
plt.grid()
plt.plot(t,sol)
plt.show()
Serge Bays
66
Lycée Les Eucalyptus
http://mathematice.fr
Exemple du pendule pesant amorti :
def f(u,t):
return [u[1],10*sin(u[0])-u[1]/4]
t=np.linspace(0,10,num=200)
sol=integ.odeint(f,[pi/2,0],t)
plt.subplot(2,1,1)
plt.grid()
plt.plot(t,sol[:,0]) # angle fonction de t
plt.subplot(2,1,2)
plt.grid()
plt.plot(sol[:,0],sol[:,1]) # diagramme de phase
plt.show()
Serge Bays
67
Lycée Les Eucalyptus
Chapitre 11
Résolution d’un système linéaire
inversible : méthode de Gauss
11.1
Matrices
Nous pouvons utiliser des listes pour représenter des matrices. Une liste composée de n listes de
longueurs p représente une matrice (n, p) (n lignes et p colonnes).
11.1.1
Création


2 2 −4
Par exemple la matrice  5 13 7  peut se définir en Python par le code suivant :
4 8
1
matrice=[[2,2,-4],[5,13,7],[4,8,1]]
a=matrice[1][2]
print(a) # affiche l’élément 7
On peut aussi créer une liste vide "matrice", puis créer les listes "ligne" une par une en les ajoutant à
la liste "matrice" :
matrice=[]
for i in range(n): # n lignes
ligne=[ . . . ] # une ligne de longueur p
matrice.append(ligne)
On pourrait envisager une autre possiblité en créant une liste composée de n listes de longueurs p où
chaque élément est initialisé avec la valeur None ou la valeur 0.
mat=2*[3*[None]] # initialisation de la matrice
for i in range(2):
for j in range(3):
mat[i][j]=i+2*j
print(mat[i])
print(mat)
# par exemple
68
http://mathematice.fr
Ce code affiche
[0, 2, 4]
[1, 3, 5]
[[1, 3, 5], [1, 3, 5]] # la première ligne a été modifiée
Donc cela ne fonctionne pas : la modification de la deuxième ligne s’est répercutée sur la première
ligne.
Un code qui fonctionne est :
mat=2*[None]
for i in range(2):
mat[i]=3*[None]
for i in range(2):
for j in range(3):
mat[i][j]=i+2*j
qui construit la matrice souhaitée :
[[0, 2, 4], [1, 3, 5]]
Pour la suite, nous allons définir une fonction matrice qui crée, avec le code précédent, une matrice
nulle (n, p) dont on pourra modifier les coefficients à volonté.
def matrice(n,p):
mat=n*[None]
for i in range(n):
mat[i]=p*[0]
return mat
ou bien, avec une construction en compréhension :
def matrice(n,p):
return [p*[0] for i in range(n)]
11.1.2
Opérations classiques
Attention, pour une matrice (n, p), les lignes sont numérotées de 0 à n − 1 et les colonnes de 0 à p − 1.
Somme de deux matrices
Pour faire la somme de deux matrices (n, p), on utilise deux boucles "for" imbriquées. On peut alors
définir une fonction somme ainsi :
Serge Bays
69
Lycée Les Eucalyptus
http://mathematice.fr
def somme(m1,m2):
n=len(m1)
# on a besoin du nombre de lignes
p=len(m1[0]) # et du nombre de colonnes
mat=matrice(n,p) # une matrice nulle
for i in range(n): # boucle sur les lignes
for j in range (p): # boucle sur les colonnes
mat[i][j]=m1[i][j]+m2[i][j]
return mat
Multiplication d’une matrice par un réel
Le principe est le même que pour la somme :
def multiple(m,k):
n=len(m)
p=len(m[0])
mat=matrice(n,p)
for i in range(n): # boucle sur les lignes
for j in range (p): # boucle sur les colonnes
mat[i][j]=k*m[i][j]
return mat
Produit de deux matrices
Pour le produit de deux matrices, c’est un peu plus compliqué et il faut vérifier que le nombre de
colonnes de la première matrice est égal au nombre de lignes de la deuxième matrice.
def produit(m1,m2):
n=len(m1)
p=len(m1[0])
q=len(m2)
r=len(m2[0])
assert p==q
mat=matrice(n,r)
for i in range(n): # boucle sur les lignes
for j in range (r): # boucle sur les colonnes
for k in range(p):
mat[i][j]+=m1[i][k]*m2[k][j]
return mat
11.2
Autres opérations
Pour appliquer l’algorithme du pivot de Gauss, il est nécessaire de définir de nouvelles opérations.
On se placera dans le cas où le système a une solution unique.
11.2.1
Recherche du pivot
A chaque étape, on recherche le plus grand pivot (en valeur absolue).
Serge Bays
70
Lycée Les Eucalyptus
http://mathematice.fr
ligne 0
ligne 1
ligne 2
ligne s
ligne s+1
ligne s+2
...
ligne n-1

2











2 −4 6
5 4 7 ... 2
13 7
3 −5 8 6 ... 4
1 −5 2 4 −3 ... 9
3 −5 2 8 ... 7
1
3 2 1 ... 9
5
5 3 2 ... 6
... ... ... ... ... ...
4 −3 2 7 ... −4












Le pivot provisoire sur l’exemple est m[s][s] = 3, et on cherche le maximum en valeur absolue des
nombres m[i][s] pour i variant de s+1 à n-1. Dans le cas où le système a une solution unique, on démontre
que ces nombres ne sont pas tous nuls.
La fonction pivot(m,s) prend en argument une matrice et le numéro du pivot que l’on cherche, (0
pour la première étape), et renvoie le numéro de la ligne contenant le pivot qui va être utilisé.
def pivot(m,s):
n=len(m)
numpiv=s # numero du pivot provisoire
for i in range(s+1,n): # boucle sur les lignes restantes
if abs(m[i][s])>abs(m[numpiv][s]):
numpiv=i
return numpiv
11.2.2
Echange de lignes
Pour échanger deux lignes d’une matrice, on commencera par faire une copie de la matrice afin de ne
pas modifier la matrice d’origine du système. On définit donc une fonction copie qui renvoie une nouvelle
matrice, copie de la matrice passée en argument :
def copie(m):
n=len(m)
p=len(m[0])
mat=matrice(n,p)
for i in range(n): # boucle sur les lignes
mat[i]=m[i][:]
return mat
On définit maintenant une fonction change(m,i,j) qui prend en argument une matrice et les numéros
des deux lignes à échanger :
def change(m,i,j):
n=len(m)
p=len(m[0])
mat=copie(m) # on fait l’échange sur une copie de la matrice
for k in range (p): # boucle sur les colonnes
mat[i][k],mat[j][k]=mat[j][k],mat[i][k]
return mat
Serge Bays
71
Lycée Les Eucalyptus
http://mathematice.fr
11.2.3
Transvection
Les transvections sont les transformations centrales dans l’algorithme du pivot de Gauss.
Si s est le numéro du pivot utilisé, on remplace chaque ligne m[i], pour i variant de s+1 à n-1, par
ai,s
Ls .
m[i]- k*m[s], où k=m[i][s]/m[s][s], soit Li ←− Li −
as,s
Avec la notation matricielle habituelle, l’algorithme est le suivant :
Pour i variant de s+1 à n-1
ai,s
k=
as,s
Pour j variant de s à p-1
ai,j = ai,j − k × as,j
def transvection(m,s): # s numero du pivot utilisé
n=len(m)
p=len(m[0])
mat=copie(m)
for i in range(s+1,n): # boucle sur les lignes
k=m[i][s]/m[s][s]
for j in range (s,p): # boucle sur les colonnes
mat[i][j]=mat[i][j]-k*mat[s][j]
return mat
11.3
Algorithme du pivot de Gauss
Le principe de l’algorithme du pivot de Gauss est d’exécuter des tâches répétitives qui fournissent à
chaque étape un système équivalent dans le but d’obtenir finalement un système triangulaire.

 2x + y − 3z = 4
−2y + 2z = 8
Voici un exemple de système triangulaire :

5z = 15
Algorithme de base :
Pour s variant de 0 à n-2
Pour i variant de s+1 à n-1
ai,s
k=
as,s
Pour j variant de s à p-1
ai,j = ai,j − k × as,j
Avec la recherche du meilleur pivot :
Serge Bays
72
Lycée Les Eucalyptus
http://mathematice.fr
Pour s variant de 0 à n-2
Recherche du pivot : piv=maxs≤i≤n−1 |ai,s |
Si piv différent de s
Echange des lignes s et piv
Pour i variant de s+1 à n-1
ai,s
k=
as,s
Pour j variant de s à p-1
ai,j = ai,j − k × as,j
11.3.1
Résolution d’un système triangulaire
On résout un système triangulaire de bas en haut : on commence par la dernière équation puis à
chaque étape, pour résoudre une équation, on substitue aux inconnues d’une ligne les valeurs trouvées
dans les lignes inférieures.


2 1 −3 4
8 
La matrice associée au système précédent est  0 −2 2
0 0
5 15
Nous allons définir une fonction solution(m) qui prend en argument une telle matrice et renvoie la
solution du système associé. Si la solution est (x0 , x1 , . . . , xn−1 ), l’algorithme est le suivant :
Pour i variant de n-1 à 0


p−2
X
1
ai,p−1 −
xi =
ai,j xj 
ai,i
j=i+1
def solution(m):
n=len(m)
p=len(m[0])
sol=n*[None] # création d’une solution "vide"
for i in range(n-1,-1,-1): # boucle sur les lignes
sol[i]=m[i][p-1]
for j in range(i+1,p-1):
sol[i]-=m[i][j]*sol[j]
sol[i]=sol[i]/m[i][i]
return sol
11.3.2
Programme final
Pour résoudre un système linéaire, il n’y a plus qu’à assembler les fonctions qui viennent d’être
étudiées.
On définit une fonction gauss(mat) qui prend en argument la matrice du système et renvoie la solution
sous la forme d’une liste (que l’on peut considérer comme une matrice colonne).
Serge Bays
73
Lycée Les Eucalyptus
http://mathematice.fr
def gauss(mat):
n=len(mat)
for s in range(n-1): # le dernier pivot est à l’avant dernière ligne
piv=pivot(mat,s)
if piv !=s:
mat=change(mat,s,piv)
mat=transvection(mat,s)
sol=solution(mat)
return sol
Complexité
La résolution finale du système nécessite n divisions et n(n − 1)/2 multiplications et soustractions.
Pour s donné, une transvection nécessite n − 1 − s divisions pour le calcul de k,
puis (n − 1 − s)(n − s + 1) multiplications et soustractions pour les nouvelles lignes ;
s variant de 0 à n − 2, on obtient donc (n − 1)n/2 divisions,
n−1
n−1
n−1
X
X
X
et
u(u + 2) =
u2 +
2u = (n − 1)n(2n − 1)/6 + (n − 1)n multiplications et soustrac1
1
1
tions, donc au total n(n + 1)/2 divisions et n3 /3 + n2 − 4n/3 multiplications et soustractions.
La complexité est en O(n3 ).
11.4
Utilisation de Numpy
La bibliothèque Numpy contient un module linalg utile en algèbre linéaire.
Par exemple pour résoudre un système MX=C :
import numpy as np
M=[[1,1,1],[1,0,-1],[-1,1,0]]
C=[[6],[-2],[1]]
X=np.linalg.solve(M,C)
print(X) # solution : [1, 2, 3]
M=[[2,2,-3],[-2,-1,-3],[6,4,4]]
C=[[2],[-5],[16]]
X=np.linalg.solve(M,C)
print(X) # solution [-14, 21, 4]
Serge Bays
74
Lycée Les Eucalyptus
Chapitre 12
Bases de Données Relationnelles
Comment gérer des données à l’aide de systèmes informatiques ? Supposons que des données sont
stockées sur un serveur qui se trouve quelque part dans le monde. Un utilisateur a besoin d’accéder à ce
serveur par un réseau afin par exemple, d’obtenir une information, de modifier des données, d’en supprimer ou d’en rajouter. L’utilisateur va écrire sa question ou requête dans un navigateur de manière simple
(formulaire, mots-clés) et cette question sera transformée en un programme dont l’exécution permettra
d’obtenir le résultat souhaité.
Le système de fichiers sur un ordinateur ou un téléphone est un système élémentaire qui permet de
gérer des données ; chaque fichier peut représenter un texte, une photo, une musique, un film, etc. On
peut effectuer des recherches, ajouter ou supprimer des fichiers. Mais interroger ou modifier des bases de
données qui peuvent être à l’echelle mondiale nécessite un système beaucoup plus complexe. Un système
de gestion de bases de données doit permettre une plus grande rapidité d’accès aux données, un mode multi
utilisateurs, assurer la sécurité, la confidentialité, l’intégrité, utiliser un langage "universel", etc.
12.1
Principes et architecture
Un système de gestion de base de données facilite la manipulation des données par l’utilisateur qui
ne doit pas se soucier de "comment cela fonctionne dans la machine" ; il est le médiateur entre la machine
et la personne.
Ce que voient les utilisateurs, l’organisation physique dans la machine et la logique de l’organisation
des données (le modèle relationnel) sont indépendants.
12.1.1
Le concept de client-serveur
L’utilisateur travaille sur une machine à l’aide d’une application ; c’est le client. La base de données
est gérée par un serveur (une autre machine). Plusieurs utilisateurs (personnes ou programmes) peuvent
effectuer des demandes au serveur simultanément.
12.1.2
Architecture trois-tiers
Le plus souvent, l’utilisateur n’accède pas directement à la base de données. C’est l’application utilisée qui communique avec le serveur de base de données. Nous distinguons alors trois niveaux : le niveau
utilisateur, le niveau applicatif et le niveau base de données.
12.2
Le modèle relationnel
Prenons un exemple. Tous les élèves de première et deuxième année peuvent avoir pendant une semaine des cours de soutien en informatique tous les jours avec un professeur qu’ils choisissent.
Pour organiser cela, on dresse donc un tableau qui ressemble à celui-ci :
75
http://mathematice.fr
NumEleve
1
2
3
4
5
6
...
Nom
Prenom
Classe
NomProf
Java
Céplus
Java
Java
Python
Céplus
Numprof
1
2
1
1
3
2
Salle
I403
I307
I403
I403
I508
I307
Trois professeurs, Mme Java, M. Céplus et M. Python, participent et chacun des trois travaille dans
sa salle.
Un tableau de ce type peut se rencontrer dans de nombreux domaines, par exemple lorsque des passagers réservent un vol Nice-Paris à une date donnée.
Lorsque le nombre de lignes devient grand, la modification d’un tel tableau peut être longue et source
de plusieurs erreurs.
Par exemple : M. Python change de salle, M. Céplus sera absent et remplacé par M. Cémoins qui est
dans une autre salle, les élèves qui avait choisi M. Céplus veulent changer pour Mme Java ...
La séparation d’objets reliés permet une avancée importante :
NumEleve
1
2
3
4
5
6
...
Nom
Numprof
1
2
3
4
Nom
Java
Céplus
Python
Cémoins
Prenom
Classe
Numprof
1
2
1
1
3
2
Salle
I403
I307
I508
I215
Les modifications sont maintenant plus simples à gérer.
Dans le modèle relationnel, les données sont organisées en tableaux à deux dimensions qui s’appelle
relations
12.2.1
Les relations
Une relation regroupe un ensemble de données homogènes concernant un même élément (ex : élèves,
professeurs, . . . ). Les données sont organisées sous forme de colonnes (ex : Nom, Prenom, . . . ). Chaque
colonne, appelée attribut, caractérise la relation. Les valeurs des attributs sont présentées sous forme de
lignes, appelées Tuples ou n-uplets et chaque n-uplet est unique ; ces valeurs ont un type (entier, texte,
flottant, ...) et appartiennent à un domaine (entier naturel inférieurs à 100, texte comportant au maximum
16 caractères, ...)
Une relation est donc un sous-ensemble, caractérisé par un nom, du produit cartésien de domaines.
Le produit cartésien d’un ensemble de domaine D1 , D2 , . . . , Dn noté D1 × D2 × . . . × Dn est
l’ensemble des n-uplets (v1 , v2 , . . . , vn ) tels, pour tout i, vi ∈ Di .
Serge Bays
76
Lycée Les Eucalyptus
http://mathematice.fr
12.2.2
Notion de clé primaire
Dans toute relation, un attribut, (ou un groupe d’attributs) permet d’identifier de manière unique les
valeurs des autres attributs. On l’appelle une clé candidate et s’il y en a plusieurs, on en privilégie une,
nommée la clé primaire. Certaines relations peuvent contenir un attribut qui est la clé primaire d’une autre
relation et qui est alors appelée clé étrangère.
Un schéma de relation se présente sous cette forme :
Relation (attribut 1, attribut 2, . . . , attribut N)
Clé primaire : attribut 1
Clé étrangère : attribut N en référence à attribut 1 de Relation X
Par exemple :
Eleves (Ideleve, Nom, Prenom, Adresse, CP, Ville, Tel, Classe)
Clé primaire : Ideleve
Clé étrangère : Classe en référence à une autre relation
Un schéma de base de données est un ensemble de schémas de relations liés par des attributs communs.
Si à une valeur d’un attribut A correspond une et une seule valeur d’un attribut B, on dit que l’attribut
B est en dépendance fonctionnelle de l’attribut A.
Par exemple : à un identifiant élève correspond un unique nom d’élève.
12.2.3
La normalisation relationnelle
Dans l’élaboration des relations, la normalisation relationnelle permet d’éviter la redondance des
données et faciliter leur mise à jour.
La première forme normale
Une relation est en première forme normale si tous ses attributs sont en dépendance fonctionnelle de
la clé primaire et ne contiennent qu’une seule information.
Ex : Eleves (Ideleve, Nom Prenom, Adresse, CP, Ville, Tel, Classe) Clé primaire : Ideleve
Ici les attributs sont en dépendance fonctionnelle de la clé primaire mais l’attribut "Nom Prenom"
contient deux informations, le nom et le prénom de l’élève ; il faut donc séparer cet attribut en deux attributs :
Eleves (Ideleve, Nom, Prenom, Adresse, CP, Ville, Tel, Classe)
La deuxième forme normale
Lorsque la clé primaire est constituée de plusieurs attributs, on dit qu’une relation est en deuxième
forme normale si elle est en première forme normale et si tous les attributs sont en dépendance fonctionnelle
de l’intégralité de la clé primaire et pas seulement que d’une partie de celle-ci.
La troisième forme normale
Une relation est en troisième forme normale si elle est en deuxième forme normale et si tous les
attributs sont en dépendance fonctionnelle directe de la clé primaire et uniquement de la clé primaire.
Eleves (Ideleve, Nom, Prenom, Adresse, CP, Ville, Tel, Classe, Salle)
Cette relation n’est pas en troisième forme normale car l’attribut Salle ne dépend pas de la clé primaire
Ideleve, mais de l’attribut Classe.
Serge Bays
77
Lycée Les Eucalyptus
http://mathematice.fr
12.3
Algèbre relationnelle
12.3.1
Vocabulaire des bases de données
Il est important d’avoir toujours en tête le vocabulaire utilisé en algèbre relationnelle et celui utilisé
avec les bases de données.
Relation = Table, Attribut = Champ = Colonne, Tuple = n-uplet = Ligne.
12.3.2
Opérateurs usuels sur les ensembles
Ces opérateurs ne s’appliquent que sur des relation compatibles : des relations A(A1 , A2 , . . . , An ) et
B(B1 , B2 , . . . , Bn ) qui ont le même nombre d’attributs et où pour tout i, les attributs Ai et Bi ont le même
domaine.
Union
A ∪ B est la relation qui inclut tous les n-uplets appartenant à A ou à B (au sens mathématiques). Les
doublons sont éliminés.
intersection
A ∩ B est la relation qui inclut tous les n-uplets appartenant à A et à B (au sens mathématiques).
Différence
A − B est la relation qui inclut tous les n-uplets appartenant à A mais pas à B.
12.3.3
Opérateurs spécifiques aux bases de données
On travaille sur les relations :
Eleves (Ideleve, Nom, Prenom, Adresse, CP, Ville, Tel, Numprof)
Profs (Id, Nom, Prenom, Tel, Salle)
Opérateur de projection
Exemple : πNom, Prenom (Eleves)
On ne retient que les n-uplets des attributs indiqués par l’opérateur, ici Nom et Prenom. Les doublons
sont éliminés.
Opérateur de sélection
Exemple : σVille=’Nice’ (Eleves)
On ne retient que les n-uplets vérifiant une propriété indiquée par l’opérateur, ici Ville=’Nice’.
Opérateur de jointure
Exemple : Eleves ./ Eleves.Numprof=Profs.Id Profs
Ceci est quivalent à une sélection sur le produit cartésien : σEleves.Numprof=Profs.Id (Eleves × Profs)
Le produit cartésien Eleves × Profs contient toutes les associations possibles entre une valeur de
Eleves et une valeur de Profs.
Serge Bays
78
Lycée Les Eucalyptus
http://mathematice.fr
Opérateur de renommage
Exemple : ρAdresse←Rue (Eleves)
Condition : les attributs Adresse et Rue ont le même domaine.
On obtient alors le nouveau schéma : Eleves (Ideleve, Nom, Prenom, Rue, CP, Ville, Tel, Numprof)
Division cartésienne
Si S et R sont deux relations, la relation S ÷ R est la plus grande relation (pour l’inclusion) telle qu’il
existe une relation R0 vérifiant ((S ÷ R) × R) ∪ R0 = S et ((S ÷ R) × R) ∩ R0 = ∅.
En particulier, si S = R1 × R2 , alors S ÷ R2 = R1 .
Serge Bays
79
Lycée Les Eucalyptus
Chapitre 13
Le langage SQL
Le SQL (Structured Query Language = langage de requêtes structuré) est un langage informatique de
dialogue avec une base de données relationnelle.
Une relation dans le modèle relationnel est une table dans le langage SQL.
Une requête est une question posée à une base de données. Nous allons voir comment sont écrites les
requêtes de base en SQL.
13.1
Les requêtes d’interrogation
13.1.1
La logique d’interrogation
Procédure
Champs (colonnes) à afficher
Tables concernées
Conditions de restriction à l’affichage
Opération relationnelle
Projection
Sélection Jointure
Ordre SQL
SELECT
FROM
WHERE
Le mot SELECT indique la liste des champs à afficher ; pour afficher tous les champs on utilise *.
Le mot FROM indique à partir de quelles tables seront extraites les informations.
Toute requête SQL se termine par un ; (point-virgule). Par convention, les instructions SQL sont
écrites en majuscule dans le code d’un programme afin de les distinguer du langage de programmation.
13.1.2
Les opérations de base
La projection
La projection permet de n’afficher qu’une partie des attributs ou champs (colonnes) d’une table.
Modèle relationnel : Eleves (Id, Nom, Prenom, Adresse, CP, Ville, Tel)
Clé primaire : Id
Requête 1 : Afficher toutes les informations concernant les élèves.
Requête SQL : SELECT * FROM Eleves ;
Requête 2 : Afficher les noms et prénoms des élèves.
Algèbre relationnelle : πN om,P renom (Eleves)
Requête SQL : SELECT Nom, Prenom FROM Eleves ;
Requête 3 : Afficher les villes dans lesquelles habitent des élèves.
Requête SQL : SELECT DISTINCT Ville FROM Eleves ;
Le mot clé Distinct permet de supprimer les doublons.
80
http://mathematice.fr
La sélection
La sélection permet de n’afficher qu’une partie des lignes d’une table.
On utilise le mot WHERE suivi du critère.
La sélection peut être monocritère ou multicritère. On utilise des opérateurs de comparaison :
= ou != peuvent être utilisés avec tout type de données ;
>, <, >=, =< sont utilisables uniquement avec des données numériques ;
On peut aussi utiliser LIKE (Comme), BETWEEN (Entre), AND (Et), OR (Ou), NOT.
Pour des recherches sur des chaînes de caractères :
% représente une chaîne de caractères quelconque ;
_ représente un caractère quelconque.
Champ au format texte ’ ... ’
Champ au format date ’mm/jj/aaaa’
Valeur de comparaison saisie par l’utilisateur [Texte à afficher]
Modèle relationnel : Eleves (Id, Nom, Prenom, Adresse, CP, Ville, Tel)
Clé primaire : Id
Requête 1 : Afficher les nom et prénom des élèves qui habitent Nice.
Algèbre relationnelle : πN om,P renom (σV ille=”N ice” (Eleves))
Requête SQL : SELECT Nom, Prenom FROM Eleves WHERE Ville= ’Nice’ ;
Requête 2 : Afficher le nom et le numéro de téléphone des élèves qui habitent à Nice ou à Cannes.
Requête SQL : SELECT Nom, Tel FROM Eleves WHERE Ville LIKE ’Nice’ OR Ville LIKE
’Cannes’ ;
Requête 3 : Afficher le nom et le prénom des élèves dont le numéro de téléphone commence par 06
et dont la première lettre du nom est comprise entre A et M.
Requête SQL : SELECT Nom, Prenom FROM Eleves WHERE Tel LIKE ’06%’ AND Nom
BETWEEN ’A’ AND ’M’ ;
La jointure
La jointure permet de mettre en relation plusieurs tables, par l’intermédiaire des liens qui existent en
particuler entre la clé primaire de l’une et la clé étrangère de l’autre.
La jointure est une opération de sélection car elle permet de ne retenir que les enregistrements pour
lesquels la valeur de la clé primaire d’une table correspond à la valeur de la clé étrangère d’une autre table.
Modèle relationnel :
Profs (Id, Nom, Prenom, Tel, Salle)
Clé primaire : Id
Eleves (Id, Nom, Prenom, Adresse, CP, Ville, Tel, Numprof)
Clé primaire : Id,
Clé étrangère : Numprof en référence à Id de Profs
Requête : Afficher le nom des élèves et la salle où aura lieu le cours avec Monsieur Python.
Algèbre relationnelle :
πEleves.N om,P rof s.Salle σP rof s.N om=0 P ython0 (Profs ./Eleves.N umprof =P rof s.Id Eleves)
Requête SQL : SELECT Eleves.Nom, Profs.Salle FROM Eleves JOIN Profs
Serge Bays
81
Lycée Les Eucalyptus
http://mathematice.fr
ON Eleves.Numprof=Profs.Id WHERE Profs.Nom=’Python’ ;
ou pour abréger : SELECT e.Nom, p.Salle FROM Eleves e JOIN Profs p
ON e.Numprof=p.Id WHERE p.Nom=’Python’ ;
Noter que c’est bien la même chose que l’extrait du produit cartésien Eleves × Profs :
SELECT Eleves.Nom, Profs.Salle FROM Eleves, Profs WHERE Eleves.Numprof=Profs.Id
AND Profs.Nom=’Python’ ;
13.1.3
Le champ calculé
On peut afficher des données résultant d’une ou plusieurs autres données et éventuellement d’un
calcul. Ces nouvelles données sont affichées dans un nouveau champ créé pour l’occasion.
Modèle relationnel : Notes (Id, Maths, Physique, SI)
Clé primaire : Id
Requête 1 : Afficher l’identifiant des copies avec la note de Maths coefficientée par 5.
Requête SQL :
SELECT Notes.Id, Notes.Maths*5 AS Points_Maths FROM Notes ;
13.1.4
Les fonctions d’agrégation
Ces fonctions permettent d’effectuer des opérations mathématiques ou des calculs statistiques sur un
ensemble d’enregistrements sélectionnés.
Compter les enregistrements
On utilise la fonction COUNT.
Le résultat de l’opération sera affiché dans un nouveau champ.
Modèle relationnel : Notes (Id, Maths, Physique, SI)
Requête 1 : Compter le nombre de copies dont la note de Physique est supérieur à 8.
Requête SQL : SELECT COUNT (Notes.Id) AS Nombre_copies FROM Notes
WHERE Notes.Physique > 8 ;
Additionner les valeurs d’un champ numérique
On utilise la fonction SUM comme la fonction COUNT avec la syntaxe SUM().
Calculer la moyenne des valeurs d’un champ numérique
On utilise la fonction AVG (average=moyenne) comme la fonction COUNT avec la syntaxe AVG ().
Afficher la valeur minimale d’un champ numérique
On utilise la fonction MIN comme la fonction COUNT avec la syntaxe MIN ().
Afficher la valeur maximale d’un champ numérique
On utilise la fonction MAX comme la fonction COUNT avec la syntaxe MAX ().
13.1.5
Les clauses de regroupement
Les clauses de regroupement permettent de réaliser des opérations sur des groupes d’enregistrements.
Serge Bays
82
Lycée Les Eucalyptus
http://mathematice.fr
La clause GROUP BY
La clause GROUP BY permet de créer des groupes d’enregistrements sur lesquels pourront être utilisées les fonctions d’agrégation. Elle est nécessaire dès lors que l’on souhaite afficher des données issues
des tables et des données issues de fonctions d’agrégation.
La syntaxe est : GROUP BY Champ1, Champ2, ...
Requête SQL : SELECT ... COUNT (...) FROM ... GROUP BY ... ;
La clause HAVING
La clause HAVING permet d’appliquer des sélections sur les regroupements créés à l’aide de la clause
GROUP BY. Contrairement à l’ordre WHERE qui sélectionne les enregistrements, la clause HAVING
sélectionne les résultats d’une fonction d’agrégation.
La syntaxe est : HAVING critères de sélection (par exemple ici " > 10 ").
Requête SQL : SELECT ... COUNT (...) FROM ... GROUP BY ... HAVING COUNT (...) > 5 ;
13.2
Les requêtes de présentation des résultats
13.2.1
Renommage de colonne
Requête SQL : SELECT moy AS ’moyenne informatique’ FROM ... WHERE ... ;
13.2.2
Ajout de texte
Requête SQL : SELECT ’L’élève’ || nom, FROM ... ;
13.2.3
Le tri
Le tri est une opération qui consiste à classer les enregistrements en fonction d’un ou plusieurs critères. La clause ORDER BY dispose de deux instructions de tri : ASC pour un tri dans l’ordre croissant et
DESC pour un tri dans l’ordre décroissant.
Modèle relationnel : Elèves (Id, Nom, Prenom, Adresse, CP, Ville, Tel, Numprof)
Profs(Id, Nom, Prenom, Tel, Salle)
Requête : afficher les noms des élèves regroupés suivant le nom de leurs professeurs.
Requête SQL : SELECT Eleves.Nom, Profs.Nom FROM Eleves, Profs
WHERE Eleves.Numprof=Profs.Id ORDER BY Eleves.Numprof ASC ;
13.3
Les requêtes de modification
Il s’agit ici de modifier des données stockées dans les tables, c’est-à-dire des lignes ou n-uplets.
13.3.1
Les requêtes d’insertion de données
Les requêtes d’insertion permettent d’ajouter un enregistrement dans une table.
La syntaxe est : INSERT INTO table (champ1, champ2, ...) VALUES (’valeur1’, ’ valeur2’, ...) ;
Modèle relationnel : Eleves (Id, Nom, Prenom, Adresse, CP, Ville, Tel, Numprof)
Serge Bays
83
Lycée Les Eucalyptus
http://mathematice.fr
Requête SQL :INSERT INTO Eleves(Nom,Numprof) VALUES (’Toto’,’4’) ;
13.3.2
Les requêtes de mise à jour de données
Les requêtes de mise à jour permettent de modifier les données stockées dans les tables.
La syntaxe est : UPDATE table SET champs à modifier WHERE sélection ;
Modèle relationnel : Eleves (Id, Nom, Prenom, Adresse, CP, Ville, Tel, Numprof)
Requête : Modifier le numéro du professeur pour un élève donné.
Requête SQL : UPDATE Eleves SET Eleves.Numprof=’4’ WHERE Eleves.Nom=’Dede’ ;
13.3.3
Les requêtes de suppression de données
Les requêtes de suppression permettent de supprimer des données stockées dans les tables. La suppression concerne l’intégralité de l’enregistrement.
La syntaxe est : DELETE FROM <nom table> WHERE <sélection> ;
13.4
Définition des données
La création de tables ou de bases de données est complexe. Ceci sera étudié en TP avec l’importation
et l’exportation de tables ou de bases.
13.4.1
Suppression d’une table
Requête SQL : DROP TABLE <nom table> ;
13.4.2
Suppression d’un attribut
Requête SQL : ALTER TABLE <nom table> DROP COLUMN <nom attribut> ;
L’ajout et l’augmentation de la taille d’un attribut seront étudiés en TP.
Serge Bays
84
Lycée Les Eucalyptus
Chapitre 14
Les bibliothèques Numpy, Matplotlib, Scipy
14.1
Calculs avec des tableaux
Si nous souhaitons établir un tableau de valeurs pour une fonction f , nous pouvons utiliser des objets
de type list.
Par exemple :
def f(x):
return x**2-3
n=11
# nombre de points en abscisse
dx=2/(n-1) # espace entre les points sur [0;2]
xliste=[i*dx for i in range(n)]
yliste=[f(x) for x in xliste]
Mais dans le cas, comme ici, où les éléments de chaque liste sont du même type et où la longueur
de chaque liste est connue, il existe dans la bibliothèque Numpy un type plus approprié et avec lequel les
calculs seront simplifiés :
import numpy as np
a=np.array(xliste)
# a est du type numpy.ndarray
La fonction np.array transforme une liste en tableau.
Note : pour la suite nous utiliserons le mot "liste" pour un objet de type "list" et le mot "tableau" pour
un objet de type "ndarray".
Pour créer un tableau de longueur n rempli de zéros, nous écrivons :
a=np.zeros(n)
Les éléments de a sont du type float ; nous pouvons spécifier le type, par exemple int :
a=np.zeros(n,int)
Nous pouvons générer un tableau de la même longueur que a où les éléments sont du même type que
ceux de a :
85
http://mathematice.fr
b=np.zeros_like(a)
Pour établir un tableau de valeurs d’une fonction, nous avons souvent besoin de générer un tableau
de n nombres uniformément répartis sur un intervalle [p ; q] :
x=np.linspace(p,q,n)
Les éléments d’un tableau peuvent être extraits commme pour les listes, mais attention, si un élément
de l’extrait est modifié, l’élément de l’original l’est aussi :
x=np.linspace(0,2,11)
# x=[ 0.
0.2 0.4
z=x[2:9:2]
# z=[ 0.4 0.8 1.2
z[1]=5
# z=[ 0.4 5.
1.2
# x=[ 0.
0.2 0.4
0.6
0.8
1.
1.2
1.4
1.6
1.8
2. ]
1.
1.2
1.4
1.6
1.8
2. ]
1.6]
1.6]
0.6 5.
Tout l’intérêt pour établir un tableau de valeur de la fonction f vue au début se voit ici :
x=np.linspace(0,2,11)
y=f(x)
Il n’y a plus besoin d’utiliser des boucles for, la fonction f s’applique directement.
Attention : les fonctions du module math ne peuvent pas s’appliquer sur les tableaux. Nous devons
utiliser les versions de ces fonctions existant dans Numpy.
x=np.linspace(0,2,11)
y=np.cos(x)*np.exp(-x**2/2)
14.2
Tracé de courbes
Nous allons utiliser la bibliothèque Numpy et le module Pyplot de la bibliothèque Matplotlib.
Le code usuel pour commencer est :
import numpy as np
import matplotlib.pyplot as plt
Le principe : on crée une liste d’abscisses et une liste d’ordonnées ; les points sont alors placés et
reliés par des segments. Le code est le suivant :
Serge Bays
86
Lycée Les Eucalyptus
http://mathematice.fr
x=[1,3,4,8]
y=[2,1,5,3]
plt.plot(x,y)
plt.savefig(’figure’) #pour sauvegarder la figure
plt.show()
On change la couleur et l’épaisseur du trait, on ajoute un titre et des étiquettes :
plt.plot(x,y,color=’red’,linewidth=6)
plt.title(’Figure 1’)
plt.xlabel(’abscisses’)
plt.ylabel(’ordonnées’)
On utilise Numpy pour les fonctions :
Serge Bays
87
Lycée Les Eucalyptus
http://mathematice.fr
def f(x):
return x**2*np.exp(-x**2)
x=np.linspace(0,3,51)
y=f(x)
plt.plot(x,y,linewidth=4)
plt.title(’Une courbe’)
plt.xlabel(’x’)
plt.ylabel(’y’)
plt.legend([’t^2*exp(-t^2)’])
plt.axis([0,3,-0.05,0.6])
plt.show()
Deux courbes sur la même figure avec la commande subplot(l,c,n) où l est le nombre de lignes, c le
nombre de colonnes et n un compteur :
def f(x):
return x**2*np.exp(-x**2)
def g(x):
return x*np.exp(-x)
x=np.linspace(0,3,51)
plt.subplot(2,1,1)
y=f(x)
plt.plot(x,y,linewidth=4)
plt.title(’Courbe 1’)
plt.xlabel(’x’)
plt.ylabel(’y’)
plt.legend([’t^2*exp(-t^2)’])
plt.axis([0,3,-0.05,0.6])
plt.subplot(2,1,2)
y=g(x)
Serge Bays
88
Lycée Les Eucalyptus
http://mathematice.fr
plt.plot(x,y,linewidth=4)
plt.title(’Courbe 2’)
plt.xlabel(’x’)
plt.ylabel(’y’)
plt.legend([’t*exp(-t)’])
plt.axis([0,3,-0.05,0.6])
plt.show()
14.3
Algèbre linéaire
Les bibliothèques Numpy et Scipy contiennent un module linalg utile en algèbre linéaire.
Exemples avec Numpy :
import numpy as np
M=[[2,2,-3],[-2,-1,-3],[6,4,4]]
C=[[2],[-5],[16]]
#resolution de MX=C
X=np.linalg.solve(M,C)
# valeurs propres de M
vp=np.linalg.eigvals(M)
N=[[1,0,0],[0,3,2],[0,0,5]]
# valeurs propres et vecteurs propres de N
valp,vecp=np.linalg.eig(N)
# determinant de N
d=np.linalg.det(N)
Serge Bays
89
Lycée Les Eucalyptus
http://mathematice.fr
# inverse de N
invN=np.linalg.inv(N)
14.4
Calcul d’intégrales
import numpy as np
import scipy.integrate as integ
def f(x):
return x**2
lx=[i/10 for i in range(11)]
ly=[f(x) for x in lx]
# méthode des trapèzes
s1=0
for i in range(10):
s1+=(lx[i+1]-lx[i])*(ly[i]+ly[i+1])/2
# avec scipy.integrate
s2=integ.trapz(ly,lx) #attention à l’ordre (ly,lx)
#calcul de l’intégrale de f entre 0 et 1
s3=integ.quad(f,0,1)
14.5
Equation f(x)=0
Dichotomie et méthode de Newton avec scipy.optimize :
import scipy.optimize
def f(x):
return x**2-2
a=1
b=2
x=scipy.optimize.bisect(f,a,b)
print("sol=",x)
x=scipy.optimize.newton(f,a)
print("sol=",x)
Les fonctions root et fsolve pour trouver des valeurs approchées des zéros d’une fonction :
import scipy.optimize
def f(x):
return x**2-2
a=1
Serge Bays
90
Lycée Les Eucalyptus
http://mathematice.fr
x=scipy.optimize.fsolve(f,a)
print("sol=",x)
x=scipy.optimize.root(f,a)
print("sol=",x)
14.6
Equations différentielles ordinaires
Pour une équation du type x0 (t) = f (x(t), t), on utilise la fonction odeint de scipy.integrate.
from math import sin, pi
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as integ
def f(x,t):
return 2*(cos(t*x))*x*(1-x/2)
t=np.linspace(0,15,num=300)
sol=integ.odeint(f,4,t)
plt.grid()
plt.plot(t,sol)
plt.show()
Le pendule pesant amorti :
def f(u,t):
return [u[1],10*sin(u[0])-u[1]/4]
t=np.linspace(0,10,num=200)
sol=integ.odeint(f,[pi/2,0],t)
plt.subplot(2,1,1)
plt.grid()
plt.plot(t,sol[:,0]) # angle fonction de t
plt.subplot(2,1,2)
plt.grid()
plt.plot(sol[:,0],sol[:,1]) #diagramme de phase
plt.show()
Pour plus d’onformations, consulter les documentations officielles :
http://matplotlib.org/contents.html
http://docs.scipy.org/doc/
Serge Bays
91
Lycée Les Eucalyptus