Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
Algorithmes et mathmatiques
Vido
Vido
Vido
Vido
Vido
Vido
partie
partie
partie
partie
partie
partie
1.
2.
3.
4.
5.
6.
>>> a=3
>>> b=6
>>> somme = a+b
>>> print(somme)
9
>>> # Les rsultats
>>> print("La somme est", somme)
La somme est 9
>>> produit = a*b
>>> print("Le produit est", produit)
Le produit est 18
On retient les choses suivantes :
On affecte une valeur une variable par le signe gal =.
On afche un message avec la fonction print().
Lorsque quune ligne contient un dise #, tout ce qui suit est ignor. Cela permet dinsrer
des commentaires, ce qui est essentiel pour relire le code.
2
Dans la suite on omettra les symboles >>>. Voir plus de dtails sur le fonctionnement en n de
section.
n = 10
somme = 0
for i in range(1,n+1) :
somme = somme + i*i*i
print(somme)
n( n+1)
2
def somme_entiers(n) :
return n*(n+1)/2
Une fonction en informatique est similaire une fonction mathmatique, cest un objet
qui prend en entre des variables (dites variables formelles ou variables muettes, ici n) et
retourne une valeur (un entier, une liste, une chane de caractres,... ici n(n+1) ).
2
3. Voici la fonction qui retourne la somme des cubes :
def somme_cubes(n) :
somme = 0
for i in range(1,n+1) :
somme = somme + i**3
return somme
n( n+1)
2
n = 12
if somme_cubes(n) == (somme_entiers(n)**2) :
print("Pour n=", n, "l'assertion est vraie.")
else :
print("L'assertion est fausse !")
On retient :
Les puissances se calculent aussi avec ** : 52 scrit 5*5 ou 5**2, 53 scrit 5*5*5 ou 5**3,...
Une fonction se dnit par def ma_fonction(variable) : et se termine par return resultat.
if condition : ... else : ... excute le premier bloc dinstructions si la condition est
vraie ; si la condition est fausse cela excute lautre bloc.
Exemple de conditions
a < b : a < b,
a <= b : a b,
a == b : a = b,
a= b ! : a = b.
Attention ! Il est important de comprendre que a==b vaut soit vraie ou faux (on compare a
et b) alors quavec a=b on affecte dans a la valeur de b.
Enn en Python (contrairement aux autres langages) cest lindentation (les espaces en dbut
de chaque ligne) qui dtermine les blocs dinstructions.
(0, 0)
(1, 0)
Travaux pratiques 3
1. Calculer laire du carr et de la portion de disque.
2. Pour un point (x, y) tir au hasard dans le carr, quelle est la probabilit que le point
soit en fait dans la portion de disque ?
3. Tirer un grand nombre de points au hasard, compter ceux qui sont dans la portion de
disque.
4. En dduire les premires dcimales de .
Voici le code :
Algorithme . pi-hasard.py
import random
Tir = 0
NbTirDansLeDisque = 0
# Numro du tir
# Nombre de tirs dans le disque
: %0.3f" %MonPi)
Commentaires :
Un petit calcul prouve que laire de la portion de disque est , laire du carr est 1. Donc la
4
probabilit de tomber dans le disque est .
4
Pour tirer un nombre au hasard on utilise une fonction random() qui renvoie un nombre rel
de lintervalle [0, 1[. Bien sr chaque appel de la fonction random() le nombre obtenu est
diffrent !
Cette fonction nest pas connue par dfaut de Python, il faut lui indiquer le nom du module
o elle se trouve. En dbut de chier on ajoute import random pour le module qui gre les
tirages au hasard. Et pour indiquer quune fonction vient dun module il faut lappeler par
module.fonction() donc ici random.random() (module et fonction portent ici le mme nom
!).
La boucle est while condition : ... Tant que la condition est vrie les instructions de
la boucle sont excutes. Ici Tir est le compteur que lon a initialis 0. Ensuite on commence
excuter la boucle. Bien sr la premire chose que lon fait dans la boucle est dincrmenter
le compteur Tir. On continue jusqu ce que lon atteigne 999. Pour Tir= 1000 la condition
nest plus vraie et le bloc dinstructions du while nest pas excut. On passe aux instructions
suivantes pour afcher le rsultat.
chaque tir on teste si on est dans la portion de disque ou pas laide de lingalit x2 + y2 1.
Cette mthode nest pas trs efcace, il faut beaucoup de tirs pour obtenir le deux premires
dcimales de .
Mini-exercices
1
1
1
1. Soit le produit P n = (1 2 ) (1 3 ) (1 1 ) (1 n ). Calculer une valeur approche
4
de P n pour les premiers entiers n.
2. Que vaut la somme des entiers i qui apparaissent dans linstruction for i in range(1,10).
Idem pour for i in range(11). Idem pour for i in range(1,10,2). Idem pour
for i in range(0,10,2). Idem pour for i in range(10,0,-1).
3. On considre le cube [0, 1] [0, 1] [0, 1] et la portion de boule de rayon 1 centre
lorigine incluse dans ce cube. Faire les calculs de probabilit pour un point tir au
hasard dans le cube dtre en fait dans la portion de boule. Faire une fonction pour le
vrier exprimentalement.
4. On lance deux ds. Exprimenter quelle est la probabilit que la somme soit 7, puis 6,
puis 3 ? Quelle est la probabilit que lun des deux ds soit un 6 ? davoir un double ? La
fonction randint(a, b) du module random retourne un entier k au hasard, vriant
a k b.
5. On lance un d jusqu ce que lon obtienne un 6. En moyenne au bout de combien de
lancer sarrte-t-on ?
et
r<b
NbDeUn = 0
for N in range(1,999+1) :
ChiffreUnite = N % 10
ChiffreDizaine = (N // 10) % 10
ChiffreCentaine = (N // 100) % 10
if (ChiffreUnite == 1) :
NbDeUn = NbDeUn + 1
if (ChiffreDizaine == 1) :
NbDeUn = NbDeUn + 1
if (ChiffreCentaine == 1) :
NbDeUn = NbDeUn + 1
print("Nombre d'occurences du chiffre '1'
:", NbDeUn)
Commentaires :
Comment obtient-on le chiffre des units dun entier N ? Cest le reste modulo 10, do
linstruction ChiffreUnite = N % 10.
Comment obtient-on le chiffre des dizaines ? Cest plus dlicat, on commence par effectuer la
division euclidienne de N par 10 (cela revient supprimer le chiffre des units, par exemple
si N = 251 alors N // 10 retourne 25). Il ne reste plus qu calculer le reste modulo 10, (par
exemple (N // 10) % 10 retourne le chiffre des dizaines 5.
Pour le chiffre des centaines on divise dabord par 100.
et a i {0, 1, . . . , 9}
a 0 est le chiffre des units, a 1 celui des dizaines, a 2 celui des centaines,...
Travaux pratiques 5
1. crire une fonction qui partir dune liste [a 0 , a 1 , . . . , a n ] calcule lentier N correspondant.
2. Pour un entier N x, combien a-t-il de chiffres ? On pourra saider dune ingalit du
type 10n N < 10n+1 .
3. crire une fonction qui partir de N calcule son criture dcimale [a 0 , a 1 , . . . , a n ].
Voici le premier algorithme :
Algorithme . decimale.py (1)
def chiffres_vers_entier(tab) :
N = 0
for i in range(len(tab)) :
N = N + tab[i] * (10 ** i)
return N
La formule mathmatique est simplement N = a n 10n + a n1 10n1 + + a 2 102 + a 1 10 + a 0 . Par
exemple chiffres_vers_entier([4,3,2,1]) renvoie lentier 1234.
Expliquons les bases sur les listes (qui sappelle aussi des tableaux)
En Python une liste est prsente entre des crochets. Par exemple pour tab = [4,3,2,1]
alors on accde aux valeurs par tab[i] : tab[0] vaut 4, tab[1] vaut 3, tab[2] vaut 2,
tab[3] vaut 1.
Pour parcourir les lments dun tableau le code est simplement for x in tab, x vaut alors
successivement 4, 3, 2, 1.
La longueur du tableau sobtient par len(tab). Pour notre exemple len([4,3,2,1]) vaut 4.
Pour parcourir toutes les valeurs dun tableau on peut donc aussi crire for i in range(len(tab)),
puis utiliser tab[i], ici i variant ici de 0 3.
La liste vide est seulement note avec deux crochets : []. Elle est utile pour initialiser une
liste.
Pour ajouter un lment une liste tab existante on utilise la fonction append. Par exemple
dnissons la liste vide tab=[], pour ajouter une valeur la n de la liste on saisit :
tab.append(4). Maintenant notre liste est [4], elle contient un seul lment. Si on continue avec tab.append(3). Alors maintenant notre liste a deux lments : [4, 3].
Voici lcriture dun entier en base 10 :
Algorithme . decimale.py (2)
def entier_vers_chiffres(N) :
tab = []
n = floor(log(N,10)) # le nombre de chiffres est n+1
for i in range(0,n+1) :
tab.append((N // 10 ** i) % 10)
return tab
8
Par exemple entier_vers_chiffres(1234) renvoie le tableau [4, 3, 2, 1]. Nous avons expliqu
tout ce dont nous avions besoin sur les listes au-dessus, expliquons les mathmatiques.
Dcomposons N sous la forme [1, 10[ [10, 100[ [100, 1000[ [1 000, 10 000[ Chaque
intervalle est du type [10n , 10n+1 [. Pour N N il existe donc n N tel que 10n N < 10n+1 .
Ce qui indique que le nombre de chiffres de N est n + 1.
Par exemple si N = 1234 alors 1 000 = 103 N < 104 = 10 000, ainsi n = 3 et le nombre de
chiffres est 4.
Comment calculer n partir de N ? Nous allons utiliser le logarithme dcimal log10 qui vrie log10 (10) = 1 et log10 (10 i ) = i. Le logarithme est une fonction croissante, donc lingalit
10n N < 10n+1 devient log10 (10n ) log10 (N) < log10 (10n+1 ). Et donc n log10 (N) < n + 1. Ce
qui indique donc que n = E(log10 (N)) o E(x) dsigne la partie entire dun rel x.
abs(x)
| x|
x ** n
xn
sqrt(x)
exp(x)
exp x
log(x)
ln x logarithme nprien
log(x,10)
floor(x)
ceil(x)
x (oor = plancher)
x (ceil = plafond)
Comme on aura souvent besoin de ce module on lappelle par le code from math import *.
Cela signie que lon importe toutes les fonctions de ce module et quen plus on na pas
besoin de prciser que la fonction vient du module math. On peut crire cos(3.14) au lieu
math.cos(3.14).
Dans lalgorithme prcdent nous avions utilis le logarithme dcimal log(x,10), ainsi que
la partie entire floor(x).
On numrote les lampes de 0 7. On souhaite contrler cette rampe : afcher toutes les combinaisons possibles, faire dler une combinaison de la gauche droite (la chenille), inverser ltat de
toutes les lampes,... Voyons comment lcriture binaire des nombres peut nous aider. Lcriture
binaire dun nombre cest son criture en base 2.
Comment calculer un nombre qui est crit en binaire ? Le chiffre des dizaines correspond 2
(au lieu de 10), le chiffre des centaines 4 = 22 (au lieu de 100 = 102 ), le chiffres des milliers
8 = 23 (au lieu de 1000 = 103 ),... Pour le chiffre des units cela correspond 20 = 1 (de mme que
100 = 1).
Par exemple 10011b vaut le nombre 19. Car
10011b = 1 24 + 0 23 + 0 22 + 1 21 + 1 20 = 16 + 2 + 1 = 19.
De faon gnrale tout entier N N scrit de manire unique sous la forme
N = a n 2n + a n1 2n1 + + a 2 22 + a 1 2 + a 0
On note alors N = a n a n1 . . . a 1 a 0
et
a i {0, 1}
Travaux pratiques 6
1. crire une fonction qui partir dune liste [a 0 , a 1 , . . . , a n ] calcule lentier N correspondant lcriture binaire a n a n1 . . . a 1 a 0 b .
2. crire une fonction qui partir de N calcule son criture binaire sous la forme
[a 0 , a 1 , . . . , a n ].
La seule diffrence avec la base 10 cest que lon calcule avec des puissances de 2.
Algorithme . binaire.py (1)
def binaire_vers_entier(tab) :
N = 0
for i in range(len(tab)) :
N = N + tab[i] * (2 ** i)
return N
Idem pour le sens inverse o lon a besoin du logarithme en base 2, qui vrie log2 (2) = 1 et
log2 (2 i ) = i.
Algorithme . binaire.py (2)
def entier_vers_binaire(N) :
tab = []
n = floor(log(N,2)) # le nombre de chiffres est n+1
for i in range(0,n+1) :
tab.append((N // 2 ** i) % 2)
return tab
Maintenant appliquons ceci notre problme de lampes. Si une lampe est allume on lui attribut
1, et si elle est teinte 0. Pour une rampe de 8 lampes on code [a 0 , a 1 , . . . , a 7 ] ltat des lampes.
Par exemple la conguration suivante :
10
20
21
22
23
24
25
26
27
def configurations(n) :
for N in range(2**(n+1)) :
print(entier_vers_binaire_bis(N,n))
O entier_vers_binaire_bis(N,n) est similaire entier_vers_binaire(N), mais en afchant aussi les zros non signicatifs, par exemple 7 en binaire scrit 111b , mais cod sur
8 chiffres on ajoute devant des 0 non signicatifs : 00000111b .
2. En criture dcimale, multiplier par 10 revient dcaler le nombre initial et rajouter un
zro. Par exemple 10 19 = 190. Cest la mme chose en binaire ! Multiplier un nombre par 2
revient sur lcriture un dcalage vers la gauche et ajout dun zro sur le chiffre des units.
Exemple : 19 = 10011b et 2 19 = 38 donc 2 10011b = 100110b .
3. Partant de N = a n a n1 . . . a 1 a 0 b . Notons N = 2N, son criture est N = a n a n1 . . . a 1 a 0 0 b .
Alors N (mod 2n+1 ) scrit exactement a n1 a n2 . . . a 1 a 0 0 b et on ajoute a n qui est le quotient
de N par 2n+1 .
Preuve : N = a n 2n+1 + a n1 2n + + a 0 2. Donc N (mod 2n+1 ) = a n1 2n + + a 0 2. Donc
N (mod 2n+1 ) + a n = a n1 2n + + a 0 2 + a n .
11
def decalage(tab) :
N = binaire_vers_entier(tab)
n = len(tab)-1 # le nombre de chiffres est n+1
NN = 2*N % 2**(n+1) + 2*N // 2**(n+1)
return entier_vers_binaire_bis(NN,n)
5. On remarque que si lon a deux congurations opposes alors leur somme vaut 2n+1 1
: par exemple avec [1, 0, 0, 1, 0, 1, 1, 1] et [0, 1, 1, 0, 1, 0, 0, 0], les deux nombres associs sont
N = 11101001b et N = 00010110b (il sagit juste de les rcrire de droite gauche). La
somme est N + N = 11101001b + 00010110b = 11111111b = 28 1. Laddition en criture
binaire se fait de la mme faon quen criture dcimale et ici il ny a pas de retenue. Si M
est un nombre avec n + 1 fois le chiffres 1 alors M + 1 = 2n+1 . Exemple si M = 11111b alors
M + 1 = 100000b = 25 ; ainsi M = 25 1. Donc loppos de N est N = 2n+1 1 N (remarquez
que dans Z/(2n+1 1)Z alors N N).
Cela conduit :
Algorithme . binaire.py (5)
def inversion(tab) :
N = binaire_vers_entier(tab)
n = len(tab)-1 # le nombre de chiffres est n+1
NN = 2**(n+1)-1 - N
return entier_vers_binaire_bis(NN,n)
Mini-exercices
1. Pour un entier n x, combien y-a-t-il doccurrences du chiffre 1 dans lcriture des
nombres de 1 n ?
2. crire une fonction qui calcule lcriture dcimale dun entier, sans recourir au log (une
boucle while est la bienvenue).
3. crire un algorithme qui permute cycliquement une conguration de rampe vers la
droite.
4. On dispose de n + 1 lampes, chaque lampe peut sclairer de trois couleurs : vert, orange,
rouge (dans cet ordre). Trouver toutes les combinaisons possibles. Comment passer
toutes les lampes la couleur suivante ?
5. Gnrer toutes les matrices 4 4 nayant que des 0 et des 1 comme coefcients. On
codera une matrice sous la forme de lignes [[1, 1, 0, 1], [0, 0, 1, 0], [1, 1, 1, 1], [0, 1, 0, 1]].
6. On part du point (0, 0) Z2 . A chaque pas on choisit au hasard un direction Nord, Sud,
Est, Ouest. Si on va au Nord alors on ajoute (0, 1) sa position (pour Sud on ajoute
(0, 1) ; pour Est (1, 0) ; pour Ouest (1, 0)). Pour un chemin dune longueur xe de
12
n pas, coder tous les chemins possibles. Caractriser les chemins qui repassent par
lorigine. Calculer la probabilit p n de repasser par lorigine. Que se passe-t-il lorsque
n + ?
7. crire une fonction, qui pour un entier N, afche son criture en chiffres romains :
M = 1000, D = 500, C = 100, X = 10, V = 5, I = 1. Il ne peut y avoir plus de trois
symboles identiques suivre.
Arctan x =
k=0
(1)k
x2k+1
x3 x5 x7
= x
+
+
2k + 1
3
5
7
Travaux pratiques 8
1. Calculer Arctan 1.
2. Calculer i = Arctan 10 i (avec 8 chiffres aprs la virgule) pour i = 1, . . . , 8.
3. Pour quelles valeurs de i, lapproximation Arctan x
x tait-elle sufsante ?
def mon_arctan(x,n) :
somme = 0
for k in range(0,n+1) :
if (k%2 == 0) : # si k est pair signe +
somme = somme + 1/(2*k+1) * (x ** (2*k+1))
else :
# si k est impair signe somme = somme - 1/(2*k+1) * (x ** (2*k+1))
return somme
La srie qui permet de calculer Arctan x est une somme innie, mais si x est petit alors
x2k+1
chacun des termes (1)k 2k+1 est trs trs petit ds que k devient grand. Par exemple si
2 k+1
1
1
x
0 x 10 alors x2k+1 102k+1 et donc pour k 4 nous aurons (1)k 2k+1 < 109 . Chacun des
termes suivants ne contribue pas aux 8 premiers chiffres aprs la virgule. Attention : il se
pourrait cependant que la somme de beaucoup de termes nissent par y contribuer, mais ce
nest pas le cas ici (cest un bon exercice de le prouver).
Dans la pratique on calcule la somme un certain ordre 2k + 1 jusqu ce que les 8 chiffres
aprs la virgules ne bougent plus. Et en fait on saperoit que lon a seulement besoin dutiliser
3
5
7
Arctan x x x + x x .
3
5
7
13
M n1
M2
M1
i n
i2
i1
M0
Rappelons que si lon a un point M(x, y) alors la rotation centre lorigine et dangle envoie
M(x, y) sur le point N(x , y ) avec
x
cos
=
y
sin
sin
cos
x
y
x = x cos y sin
y = x sin + y cos
cest--dire
Pour un point M, on note M le point de la demi-droite [ON) tel que les droites (OM) et (MM )
soient perpendiculaires en M.
M
Mn
N
tan a
yn
xn
yn
a
M
O
xn
Travaux pratiques 9
1.(a) Calculer la longueur OM .
(b) En dduire les coordonnes de M .
(c) Exprimez-les uniquement en fonction de x, y et tan .
2. Faire une boucle qui dcompose langle a en somme dangles i ( une prcision de 108
; avec un minimum dangles, les angles pouvant se rpter).
14
3. Partant de M0 = (1, 0) calculer les coordonnes des diffrents M k , jusquau point
yn
M n (xn , yn ) correspondant lapproximation de langle a. Renvoyer la valeur xn comme
approximation de tan a.
Voici les prliminaires mathmatiques :
OM
OM
Dans le triangle rectangle OMM on a cos = OM donc OM = cos .
Dautre part comme la rotation dangle conserve les distances alors OM = ON. Si les
1
1
coordonnes de M sont (x , y ) alors x = cos x et y = cos y .
Ainsi
1
1
x = cos x = cos x cos y sin = x y tan
1
1
y = cos y = cos x sin + y cos = x tan + y
Autrement dit :
x
y
1
tan
tan
1
x
y
Voici une boucle simple pour dcomposer langle : on commence par retirer le plus grand angle
0 autant de fois que lon peut, lorsque ce nest plus possible on passe langle 1 ,...
Algorithme . tangente.py (2)
i = 0
while (a > precision) :
# boucle tant que la precision pas atteinte
while (a < theta[i]) : # choix du bon angle theta_i soustraire
i = i+1
a = a - theta[i]
# on retire l'angle theta_i et on recommence
Ici precision est la prcision souhait (pour nous 109 ). Et le tableau theta contient les valeurs
des angles i .
x0
Posons x0 = 1, y0 = 0 et M0 =
. Alors on dnit par rcurrence M k+1 = P( i ) M k o P( ) =
y0
1
tan
. Les i sont ceux apparaissant dans la dcomposition de langle en somme de
tan
1
i , donc on connat tan i = 10 i . Ainsi si lon passe dun point M k M k+1 par un angle i on a
simplement :
xk+1 = xk yk 10 i
yk+1 = xk 10 i + yk
y
n
La valeur xn est la tangente de la somme des angles i , donc une approximation de tan a.
Le code est maintenant le suivant.
def ma_tan(a) :
precision = 10**(-9)
i = 0 ; x = 1 ; y = 0
while (a > precision) :
while (a < theta[i]) :
i = i+1
newa = a - theta[i]
newx = x - (10**(-i))*y
newy = (10**(-i))*x + y
15
x = newx
y = newy
a = newa
return y/x
# on renvoie la tangente
1
.
cos2 x
On en
1+tan x
Donc une fois que lon a calcul tan x on en dduit sin x et cos x par un calcul de racine carre.
Attention cest valide car x est compris entre 0 et . Pour un x quelconque il faut se ramener par
2
les formules trigonomtriques lintervalle [0, ].
2
Mini-exercices
1. On dispose de billets de 1, 5, 20 et 100 euros. Trouvez la faon de payer une somme de
n euros avec le minimum de billets.
2. Faire un programme qui pour nimporte quel x R, calcule sin x, cos x, tan x.
x
2
3. Pour t = tan 2 montrer que tan x = 1tt2 . En dduire une fonction qui calcule tan x. (Utiliser que pour x assez petit tan x x).
4. Les rels
Dans cette partie nous allons voir diffrentes faons de calculer la constante dEuler. Cest un
nombre assez mystrieux car personne ne sait si est un nombre rationnel ou irrationnel. Notre
objectif est davoir le plus de dcimales possibles aprs la virgule en un minimum dtapes. Nous
verrons ensuite comment les ordinateurs stockent les rels et les problmes que cela engendre.
16
1 1 1
1
+ + ++
1 2 3
n
et dnissons
u n = H n ln n.
Cette suite (u n ) admet une limite lorsque n + : cest la constante dEuler.
Travaux pratiques 11
1. Calculer les premires dcimales de . Sachant que u n
exactes peut-on esprer avoir obtenues ?
1
2n ,
combien de dcimales
1
1
2. On considre vn = H n ln n + 1 + 24n . Sachant vn 48n3 , calculer davantage de
2
dcimales.
def euler1(n) :
somme = 0
for i in range(n,0,-1) :
somme = somme + 1/i
return somme - log(n)
Algorithme . euler.py (2)
def euler2(n) :
somme = 0
for i in range(n,0,-1) :
somme = somme + 1/i
return somme - log(n+1/2+1/(24*n))
Vous remarquez que la somme est calcule partir de la n. Nous expliquerons pourquoi en n de
section.
C
e4n
17
Travaux pratiques 12
1. Programmer cette mthode.
2. Combien ditrations faut-il pour obtenir 1000 dcimales ?
3. Utiliser le module decimal pour les calculer.
Voici le code :
Algorithme . euler.py (3)
def euler3(n) :
alpha = 3.59112147
N = floor(alpha*n)
# Borne des sommes
A = 0 ; B = 0
H = 0
for k in range(1,N+1) :
c = ( (n**k)/factorial(k) ) ** 2
# Coefficient commun
H = H + 1/k
# Somme harmonique
A = A + c*H
B = B + c
return A/B - log(n)
1
Pour obtenir N dcimales il faut rsoudre linquation eCn 10N . On passe au log pour obtenir
4
n N ln(10)+ln(C ) . On ne connat pas C mais ce nest pas si important. Moralement pour une itration
4
de plus on obtient ( peu prs) une dcimale de plus (cest--dire un facteur 10 sur la prcision !).
Pour n 800 on obtient 1000 dcimales exactes de la constante dEuler :
0,
57721566490153286060651209008240243104215933593992
35988057672348848677267776646709369470632917467495
14631447249807082480960504014486542836224173997644
92353625350033374293733773767394279259525824709491
60087352039481656708532331517766115286211995015079
84793745085705740029921354786146694029604325421519
05877553526733139925401296742051375413954911168510
28079842348775872050384310939973613725530608893312
67600172479537836759271351577226102734929139407984
30103417771778088154957066107501016191663340152278
93586796549725203621287922655595366962817638879272
68013243101047650596370394739495763890657296792960
10090151251959509222435014093498712282479497471956
46976318506676129063811051824197444867836380861749
45516989279230187739107294578155431600500218284409
60537724342032854783670151773943987003023703395183
28690001558193988042707411542227819716523011073565
83396734871765049194181230004065469314299929777956
93031005030863034185698032310836916400258929708909
85486825777364288253954925873629596133298574739302
Pour obtenir plus de dcimales que la prcision standard de Python, il faut utiliser le module
decimal qui permet de travailler avec une prcision arbitraire xe.
18
exposant
pour 1, 234 . . . 10123 . La mantisse est un nombre dcimal (positif ou ngatif) appartenant
[1, 10[ et lexposant est un entier (lui aussi positif ou ngatif). En Python la mantisse une
prcision de 16 chiffres aprs la virgule.
Cette ralit informatique fait que des erreurs de calculs peuvent apparatre mme avec des
oprations simples. Pour voir un exemple de problme faites ceci :
Travaux pratiques 13
Poser x = 1016 , y = x + 1, z = y 1. Que vaut z pour Python ?
Comme Python est trs prcis nous allons faire une routine qui permet de limiter drastiquement
le nombre de chiffres et mettre en vidence les erreurs de calculs.
Travaux pratiques 14
1. Calculer lexposant dun nombre rel. Calculer la mantisse.
2. Faire une fonction qui ne conserve que 6 chiffres dun nombre (6 chiffres en tout : avant
+ aprs la virgule, exemple 123, 456789 devient 123, 456).
Voici le code :
Algorithme . reels.py (1)
precision = 6
# Nombre de dcimales conserves
def tronquer(x) :
n = floor(log(x,10))
# Exposant
m = floor( x * 10 ** (precision-1 - n)) # Mantisse
return m * 10 ** (-precision+1+n)
# Nombre tronqu
Absorption
19
Travaux pratiques 15
1. Calculer tronquer(1234.56 + 0.007).
2. Expliquer.
Chacun des nombres 1234, 56 et 0, 007 est bien un nombre scrivant avec moins de 6 dcimales
mais leur somme 1234, 567 a besoin dune dcimale de plus, lordinateur ne retient pas la 7-me
dcimale et ainsi le rsultat obtenu est 1234, 56. Le 0, 007 napparat pas dans le rsultat : il a t
victime dune absorption.
limination
Travaux pratiques 16
1. Soient x = 1234, 8777, y = 1212, 2222. Calculer x y la main. Comment se calcule la
diffrence x y avec notre prcision de 6 chiffres ?
2. Expliquer la diffrence.
Comme x y = 22, 6555 qui na que 6 chiffres alors on peut penser que lordinateur va obtenir
ce rsultat. Il nen est rien, lordinateur ne stocke pas x mais tronquer(x), idem pour y. Donc
lordinateur effectue en fait le calcul suivant : tronquer(tronquer(x)-tronquer(y)), il calcule
donc 1234, 87 1212, 22 = 22, 65. Quel est le problme ? Cest quensuite lutilisateur considre
tort que le rsultat est calcul avec une prcision de 6 chiffres. Donc on peut penser que le
rsultat est 22, 6500 mais les 2 derniers chiffres sont une pure invention.
Cest un phnomne dlimination. Lorsque lon calcule la diffrence de deux nombres proches,
le rsultat a en fait une prcision moindre. Cela peut tre encore plus dramatique avec lexemple
= 1234, 569 1234, 55 la diffrence est 0, 01900 alors que lordinateur retournera 0, 01000. Il y a
presque un facteur deux, et on aura des problmes si lon a besoin de diviser par .
Signalons au passage une erreur dinterprtation frquente : ne pas confondre la prcision
dafchage (exemple : on calcule avec 10 chiffres aprs la virgule) avec lexactitude du rsultat
(combien de dcimales sont vraiment exactes ?).
et
20
un nombre en criture binaire qui sen rapproche le plus ; lorsquon lui demande dafcher le
nombre stock, il retourne lcriture dcimale qui se rapproche le plus du nombre stock, mais ce
nest plus 0, 2, mais un nombre trs trs proche :
0.2000000000000000111022302. . .
1
12
1
1
1
+ 22 + 32 + + n2 .
2. Faire une fonction qui calcule cette somme mais en utilisant seulement une criture
dcimale 6 chiffres ( laide de la fonction tronquer() vue au-dessus).
3. Reprendre cette dernire fonction, mais en commenant la somme par les plus petits
termes.
4. Comparez le deux dernires mthodes, justier et conclure.
La premire fonction ne pose aucun problme et utilise toute la prcision de Python.
Dans la seconde on doit, chaque calcul, limiter notre prcision 6 chiffres (ici 1 avant la virgule
et 5 aprs).
Algorithme . reels.py (2)
def somme_inverse_carres_tronq(n) :
somme = 0
for i in range(1,n+1) :
somme = tronquer(somme + tronquer(1/(i*i)))
return somme
def somme_inverse_carres_tronq_inv(n) :
somme = 0
for i in range(n,0,-1) :
somme = tronquer(somme + tronquer(1/(i*i)))
return somme
Par exemple pour n = 100 000 lalgorithme somme_inverse_carres_tronq() (avec criture tronque, somm dans lordre) retourne 1, 64038 alors que lalgorithme somme_inverse_carres_tronq_inv()
(avec la somme dans lordre inverse) on obtient 1, 64490. Avec une prcision maximale et n trs
2
grand on doit obtenir 1, 64493 . . . (en fait cest ).
6
Notez que faire grandir n pour lalgorithme somme_inverse_carres_tronq() ny changera rien, il
bloque 2 dcimales exactes aprs la virgule : 1, 64038 ! La raison est un phnomne dabsorption
: on rajoute des termes trs petits devant une somme qui vaut plus de 1. Alors que si lon part
21
des termes petits, on ajoute des termes petits une somme petite, on garde donc un maximum de
dcimales valides avant de terminer par les plus hautes valeurs.
Mini-exercices
1. crire une fonction qui approxime la constante qui vrie (ln 1) = 1. Pour cela
poser f (x) = x(ln x 1) 1 et appliquer la mthode de Newton : xer u 0 (par exemple ici
f (u )
u 0 = 4) et u n+1 = u n f (un ) .
n
2. Pour chacune des trois mthodes, calculer le nombre approximatif ditrations ncessaires pour obtenir 100 dcimales de la constante dEuler.
3. Notons C n =
1
4n
[(2 k)!]3
2n
.
k=0 ( k!)4 (16 n)2 k
An
Bn
n
B2
n
1
3
et u n+1 = 4u n 1.
def factorielle_classique(n) :
produit = 1
for i in range(1,n+1) :
produit = i * produit
return produit
Voyons comment fonctionne cette boucle. On initialise la variable produit 1, on fait varier un
indice i de 1 n. chaque tape on multiplie produit par i et on affecte le rsultat dans produit.
Par exemple si n = 5 alors la variable produit sinitialise 1, puis lorsque i varie la variable
produit devient 1 1 = 1, 2 1 = 2, 3 2 = 6, 4 6 = 24, 5 24 = 120. Vous avez bien sr reconnus le
calcul de 5!
tudions un autre algorithme.
22
def factorielle(n) :
if (n==1) :
return 1
else :
return n * factorielle(n-1)
Que fait cet algorithme ? Voyons cela pour n = 5. Pour n = 5 la condition du si (if) nest pas
vrie donc on passe directement au sinon (else). Donc factorielle(5) renvoie comme rsultat
: 5 * factorielle(4). On a plus ou moins progress : le calcul nest pas ni car on ne connat
pas encore factorielle(4) mais on sest ramen un calcul au rang prcdent, et on itre :
et enn factorielle(5) = 5 * 4 * 3 * 2 * factorielle(1). Pour factorielle(1) la condition du if (n==1) est vrie et alors factorielle(1)=1. Le bilan est donc que factorielle(5) = 5 * 4 * 3 *
cest bien 5!
Une fonction qui lorsque elle sexcute sappelle elle-mme est une fonction rcursive. Il y a une
analogie trs forte avec la rcurrence. Par exemple on peut dnir la suite des factorielles ainsi :
u1 = 1
et
u n = n u n1 si n
2.
def fibonacci(n) :
if (n==0) or (n==1) :
return 1
else :
return fibonacci(n-1)+fibonacci(n-2)
Faites-le calcul de fibonacci(5). Voici la version mathmatique des nombres de Fibonacci.
F0 = 1, F1 = 1
F n = F n1 + F n2
et
si n
2.
13
21
34
...
23
Travaux pratiques 19
1. Crer une fonction rcursive pgcd(a,b) qui calcule le pgcd.
2. On note p n la probabilit que deux entiers a, b tirs au hasard dans 1, 2, . . . , n soient
premiers entre eux. Faire une fonction qui approxime p n . Lorsque n devient grand,
6
comparer p n et 2 .
Voici le code pour lalgorithme dEuclide rcursif. Notez quel point le code est succinct et pur !
Algorithme . arith.py (1)
def pgcd(a,b) :
if a%b == 0 :
return b
else :
return pgcd(b, a%b)
Deux entiers a, b sont premiers entre eux ssi pgcd(a, b) = 1, donc voici lalgorithme :
Algorithme . arith.py (2)
def nb_premiers_entre_eux(n,nbtirages) :
i = 1
nbpremiers = 0
while i <= nbtirages :
i = i+1
a = random.randint(1,n)
b = random.randint(1,n)
if pgcd(a,b)==1 :
nbpremiers = nbpremiers + 1
return nbpremiers
On tire au hasard deux entiers a et b entre 1 et n et on effectue cette opration nbtirages fois.
Par exemple entre 1 et 1000 si lon effectue 10 000 tirage on trouve une probabilit mesure par
nbpremiers/nbtirages de 0, 60 . . . (les dcimales daprs dpendent des tirages).
6
Lorsque n tend vers + alors p n 2 = 0.607927 . . . et on dit souvent que : la probabilit que
6
deux entiers tirs au hasard soient premiers entre eux est 2 .
Commentaires sur les algorithmes rcursifs :
Les algorithmes rcursifs ont souvent un code trs court, et proche de la formulation mathmatique lorsque lon a une relation de rcurrence.
Selon le langage ou la fonction programme il peut y avoir des problmes de mmoire (si par
exemple pour calculer 5! lordinateur a besoin de stocker 4! pour lequel il a besoin de stocker
3!...).
Il est important de bien rchir la condition initiale (qui est en fait celle qui termine
lalgorithme) et la rcurrence sous peine davoir une fonction qui boucle indniment !
24
Il nexiste pas des algorithmes rcursifs pour tout (voir par exemple les nombres premiers)
mais ils apparaissent beaucoup dans les algorithmes de tris. Autre exemple : la dichotomie
se programme trs bien par une fonction rcursive.
def est_premier(n) :
if (n<=1) : return False
k = 2
while k*k <= n :
if n%k==0 :
return False
else :
k = k +1
return True
Notez quil vaut mieux crire la condition k*k <= n plutt que k <= sqrt(n) : il est beaucoup plus rapide de calculer le carr dun entier plutt quextraire une racine carre.
Nous avons utilis un nouveau type de variable : un boolen est une variable qui ne
peut prendre que deux tats Vrai ou Faux (ici True or False, souvent cod 1 et 0). Ainsi
est_premier(13) renvoie True, alors que est_premier(14) renvoie False.
2. Pour le crible dEratosthne le plus dur est de trouver le bon codage de linformation.
25
def eratosthene(n) :
liste_entiers = list(range(n+1)) # tous les entiers
liste_entiers[1] = 0
# 1 n'est pas premier
k = 2
# on commence par les multiples de 2
while k*k <= n :
if liste_entiers[k] != 0 : # si le nombre k n'est pas barr
i = k
# les i sont les multiples de k
while i <= n-k :
i = i+k
liste_entiers[i] = 0 # multiples de k : pas premiers
k = k +1
liste_premiers = [k for k in liste_entiers if k !=0] # efface les 0
return liste_premiers
Ici on commence par faire un tableau contenant les entiers [0,1,2,3,4,5,6,7,8,9,10,11,12,13,...].
Pour signier quun nombre nest pas premier ou remplace lentier par 0. Comme 1
nest pas un nombre premier : on le remplace par 0. Puis on fait une boucle, on part
de 2 et on remplace tous les autres multiples de 2 par 0 : la liste est maintenant :
[0,0,2,3,0,5,0,7,0,9,0,11,0,13,...]. Le premiers nombre aprs 2 est 3 cest donc un
nombre premier. (car sil na aucun diviseur autre que 1 et lui-mme car sinon il aurait t
ray). On garde 3 et remplace tous les autres multiples de 3 par 0. La liste est maintenant
: [0,0,2,3,0,5,0,7,0,0,0,11,0,13,...]. On itre ainsi, la n on efface les zros pour
obtenir : [2,3,5,7,11,13,...].
3. Pour la spirale dUlam la seule difcult est de placer les entiers sur une spirale, voici le
rsultat.
26
gauche le dbut de la spirale (de n = 1 37) en rouge les nombres premiers (en noir les
nombres non premiers) ; droite le motif obtenu jusqu de grandes valeurs (en blanc les
nombres non premiers).
Mini-exercices
1. crire une version itrative et une version rcursive pour les fonctions suivantes : (a)
la somme des carrs des entiers de 1 n ; (b) 2n (sans utiliser dexposant) ; (c) la partie
entire dun rel x 0 ; (d) le quotient de la division euclidienne de a par b (avec a N,
b N ) ; (e) le reste de cette division euclidienne (sans utiliser les commandes % ni //).
2. crire une version itrative de la suite de Fibonacci.
3. crire une version itrative de lalgorithme dEuclide. Faire une version qui calcule les
coefcients de Bzout.
4. crire une fonction itrative, puis rcursive, qui pour un entier n renvoie la liste de ses
diviseurs. Dessiner une spirale dUlam, dont lintensit de la couleur dpend du nombre
de diviseurs.
5. Une suite de Syracuse est dnie ainsi : partant dun entier sil est pair on le divise par
deux, sil est impair on le multiplie par 3 et on ajoute 1. On itre ce processus. Quelle
conjecture peut-on faire sur cette suite ?
6. Dessiner le triangle de Pascal
1
2
mieux : remplacer les coefcients pairs par un carr blanc et les coefcients impairs
par un carr rouge). Quelle gure reconnaissez-vous ?
27
programme fait bien ce que lon souhaite) et ceci en un nombre ni dtapes (cela renvoie le
rsultat en temps ni).
Maintenant certains algorithmes peuvent tre plus rapides que dautres. Cest souvent le temps
de calcul qui est le principal critre, mais cela dpend du langage et de la machine utilise. Il
existe une manire plus mathmatique de faire : la complexit dun algorithme cest le nombre
doprations lmentaires effectuer.
Ces oprations peuvent tre le nombre doprations au niveau du processeur, mais pour nous ce
sera le nombre dadditions +, le nombre de multiplications effectuer. Pour certains algorithmes
la vitesse dexcution nest pas le seul paramtre mais aussi la taille de la mmoire occupe.
6.2. Polynmes
Travaux pratiques 21
On code un polynme a 0 + a 1 X + + a n X n sous la forme dune liste [a 0 , a 1 , . . . , a n ].
1. crire une fonction correspondant la somme de deux polynmes. Calculer la complexit
de cet algorithme (en terme du nombre dadditions sur les coefcients, en fonctions du
degr des polynmes).
2. crire une fonction correspondant au produit de deux polynmes. Calculer la complexit
de cet algorithme (en terme du nombre dadditions et de multiplications sur les coefcients).
3. crire une fonction correspondant au quotient et au reste de la division euclidienne de
A par B o B est un polynme unitaire (son coefcient de plus haut degr est 1). Majorer
la complexit de cet algorithme (en terme du nombre dadditions et de multiplications
sur les coefcients).
1. La seule difcult est de grer les indices, en particulier on ne peut appeler un lment
dune liste en dehors des indices o elle est dnie. Une bonne ide consiste commencer
par dnir une fonction degre(poly), qui renvoie le degr du polynme (attention au 0 non
signicatifs).
Voici le code dans le cas simple o deg A = deg B :
Algorithme . polynome.py (1)
def somme(A,B) :
# si deg(A)=deg(B)
C = []
for i in range(0,degre(A)+1) :
s = A[i]+B[i]
C.append(s)
m
i
i =0 a i X ,
B(X ) =
n
j
j =0 b j X
et C = A B =
28
def produit(A,B) :
C = []
for k in range(degre(A)+degre(B)+1) :
s = 0
for i in range(k+1) :
if (i <= degre(A)) and (k-i <= degre(B)) :
s = s + A[i]*B[k-i]
C.append(s)
return C
Pour la complexit on commence par compter le nombre de multiplications (dans Z ou R).
Notons m = deg A et n = deg B. Alors il faut multiplier les m + 1 coefcients de A par les n + 1
coefcients de B : il y a donc (m + 1)(n + 1) multiplications.
Comptons maintenant les additions : les coefcients de A B sont : c 0 = a 0 b 0 , c 1 = a 0 b 1 +
a 1 b 0 , c 2 = a 2 b 0 + a 1 b 1 + a 2 b 0 ,...
Nous utilisons lastuce suivante : nous savons que le produit A B est de degr m + n donc a
(au plus) m + n + 1 coefcients. Partant de (m + 1)(n + 1) produits, chaque addition regroupe
deux termes, et nous devons arriver m + n + 1 coefcients. Il y a donc (m + 1)(n + 1) (m +
n + 1) = mn additions.
3. Pour la division euclidienne, le principe est de poser une division de polynme. Par exemple
pour A = 2X 4 X 3 2X 2 + 3X 1 et B = X 2 X + 1.
2X 4 X 3 2X 2 + 3X 1
X2 X +1
2X 4 2X 3 + 2X 2
X 3 4X 2 + 3X 1
2X 2 + X 3
X3 X2 + X
3X 2 + 2X 1
3X 2 + 3X 3
X + 2
Alors on cherche quel monme P1 fait diminuer le degr de A P1 B, cest 2X 2 (le coefcient 2
est le coefcient dominant de A). On pose ensuite R 1 = A P1 B = X 3 4X 2 + 3X 1, Q 1 = 2X 2 ,
on recommence avec R 1 divis par B, R 2 = R 1 P2 B avec P2 = X , Q 2 = Q 1 + P2 ,... On arrte
lorsque deg R i < deg B.
Algorithme . polynome.py (3)
def division(A,B) :
Q = [0]
# Quotient
R = A
# Reste
while (degre(R) >= degre(B)) :
29
P = monome(R[degre(R)],degre(R)-degre(B))
R = somme(R,produit(-P,B))
Q = somme(Q,P)
return Q,R
Cest une version un peu simplie du code : o P = r n X deg R deg B et o il faut remplacer
P par [a 0 , a 1 , ...]. Si A, B Z[X ] alors le fait que B soit unitaire implique que Q et R sont
aussi coefcients entiers.
Quelle est la complexit de la division euclidienne ? chaque tape on effectue une multiplication de polynmes (P i B) puis une addition de polynme (R i P i B) ; chaque tape le
degr de R i diminue (au moins) de 1. Donc il y a au plus deg A deg B + 1 tapes.
Mais dans la pratique cest plus simple que cela. La multiplication P i B est trs simple :
car P i est un monme P i = p i X i . Multiplier par X i cest juste un dcalage dindice (comme
multiplier par 10 i en criture dcimale) cest donc une opration ngligeable. Il reste donc
multiplier les coefcients de B par p i : il y a donc deg B + 1 multiplications de coefcients.
La soustraction aussi est assez simple on retire R i un multiple de B, donc on a au plus
deg B + 1 coefcients soustraire : il y a chaque tape deg B + 1 additions de coefcients.
Bilan : si m = deg A et n = deg B alors la division euclidienne seffectue en au plus (m n +
1)(m + 1) multiplications et le mme nombre dadditions (dans Z ou R).
et
Q = Q1 + Q2 X n
30
def decoupe(P,n) :
if (degre(P)<n) : return P, [0]
else : return P[0 :n], P[n :]
On a aussi besoin dune fonction produit_monome(P,n) qui renvoie le polynme X n P
par un dcalage. Voici la multiplication proprement dite avec les appels rcursifs et leur
combinaison.
Algorithme . polynome.py (5)
def produit_assez_rapide(P,Q) :
p = degre(P) ; q = degre(Q)
if (p == 0) : return [P[0]*k for k in Q]
if (q == 0) : return [Q[0]*k for k in P]
n = (max(p,q)+1)//2
P1,P2 = decoupe(P,n)
Q1,Q2 = decoupe(Q,n)
P1Q1 = produit_assez_rapide(P1,Q1)
P2Q2 = produit_assez_rapide(P2,Q2)
P1Q2 = produit_assez_rapide(P1,Q2)
P2Q1 = produit_assez_rapide(P2,Q1)
R1 = produit_monome(somme(P1Q2,P2Q1),n)
R2 = produit_monome(P2Q2,2*n)
return somme(P1Q1,somme(R1,R2))
# dcalages
# sommes
La relation de rcurrence qui exprime la complexit de cet algorithme est C(n) = 4C(n/2) +
O(n) et elle se rsout en C(n) = O(n2 ). Voir la question suivante pour une mthode de rsolution.
3.
31
def produit_rapide(P,Q) :
p = degre(P) ; q = degre(Q)
if (p == 0) : return [P[0]*k for k in Q] # Condition initiale : P=cst
if (q == 0) : return [Q[0]*k for k in P] # Condition initiale : Q=cst
n = (max(p,q)+1)//2
# demi-degr
P1,P2 = decoupe(P,n)
# decoupages
Q1,Q2 = decoupe(Q,n)
P1Q1 = produit_rapide(P1,Q1)
# produits en petits degrs
P2Q2 = produit_rapide(P2,Q2)
PQ = produit_rapide(somme(P1,P2),somme(Q1,Q2))
R1 = somme(PQ,somme([-k for k in P1Q1],[-k for k in P2Q2]))
R1 = produit_monome(R1,n)
# dcalages
R2 = produit_monome(P2Q2,2*n)
return somme(P1Q1,somme(R1,R2))
# sommes
puis pour n = 2
2
3
+1
+ 0 = 3 1
2
3
C (2 )
3
+1
qui vrie =
2
1 + 3
+1
C(n) = C(2 ) = 3 = (3
+1
) + (1 )3 = O(3 ) = O(2
ln 3
ln 3
ln 2
ln 3
) = O(n ln 2 )
O(n1.585 ).
32
Mini-exercices
1. Faire une fonction qui renvoie le pgcd de deux polynmes.
2. Comparer les complexits des deux mthodes suivantes pour valuer un polynme P
n
n
en une valeur x0 R : P(x0 ) = a 0 + a 1 x0 + + a n1 x0 1 + a n x0 et P(x0 ) = a 0 + x0 a 1 +
x0 a 2 + + x0 (a n1 + a n x0 )
(mthode de Horner).
3. Comment trouver le maximum dune liste ? Montrer que votre mthode est de complexit minimale (en terme du nombre de comparaisons).
4. Soit f : [a, b] R une fonction continue vriant f (a) f (b) 0. Combien ditrations de
la mthode de dichotomie sont ncessaires pour obtenir une racine de f (x) = 0 avec une
prcision infrieure ?
5. Programmer plusieurs faons de calculer les coefcients du binme de Newton
comparer.
n
k
et les
Auteurs
Rdaction : Arnaud Bodin
Relecture : Jean-Franois Barraud
Remerciements Lionel Rieg pour son tp sur lalgorithme de Karatsuba