Université de Nice-Sophia Antipolis Deug MIAS-MI 1
Algorithmique & Programmation 2002–2003
TP N 5
Analyse des performances
Buts :
Analyser les performances d’un programme.
Etre capable de comprendre la complexité d’un algorithme.
1 Exponentiation de grands entiers
Le but de cette section est de réaliser des fonctions permettant de calculer des puissances
entières de grands entiers. Les grands entiers existent déjà en Java, il s’agit du type long qui
permet de représenter des valeurs entières signées comprises entre et
(c’est à dire entre et , donc codées sur 64 bits)1. Vous allez
implémenter deux algorithmes pour le calcul de , où est un entier de type long et un
entier de type int.
1.1 Première méthode : algorithme naïf
a. Écrivez une fonction myPow1 qui prend en argument un entier positif de type long et un
entier positif de type int, et qui calcule suivant l’algorithme ci-dessous.
fonction myPow1 (n : entier_long, m : entier) : entier_long
variables
res : entier_long 1
i : entier
début
pour ide 1àmfaire
res n
finpour
retourner res
fin
Il est facile de constater que cet algorithme a une complexité en . En effet, il y a pas-
sages dans la boucle et une opération par passage.
b. Écrivez une méthode main dans votre classe pour tester votre fonction (n’oubliez pas de
prévoir les erreurs de saisie).
1.2 Seconde méthode : algorithme paresseux
c. Écrivez une fonction myPow2 qui prend les mêmes arguments que la fonction précédente,
mais qui suit l’algorithme ci-dessous.
1. Il existe également la classe java.math.BigInteger qui permet de gérer des entiers de taille quelconque et donc
encore plus longs. Nous ne la manipulerons pas lors de cette séance.
1
fonction myPow2 (n : entier_long, m : entier) : entier long
variables
cmpt : entier m
a : entier_long 1
b : entier_long n
début
tantque cmpt > 1 faire
si cmpt est pair alors
a b
finsi
b b
cmpt 2
fintantque
retourner a b
fin
Proposition 1 Cet algorithme calcule avec une complexité en .
Preuve Montrons d’abord la terminaison de l’algorithme2. Nous pouvons remarquer que (cmpt)
constitue une suite décroissante d’entiers strictement positifs puisque lors de chaque itération
cmpt est divisé par 2. La condition d’arrêt de la boucle sera donc bien atteinte et cela garantit que
l’algorithme se termine.
Montrons maintenant la correction de l’algorithme, c’est-à-dire qu’il calcule bien . Cela va
se faire par récurrence grâce à l’invariant de boucle suivant : à chaque itération, cmpt .
Ceci se montre par récurrence:
Initialisation : au début, par définition, cmpt .
On note par , et les valeurs de a,bet cmpt à l’itération . Supposons alors que
et que . Alors, on a , et . On
en déduit que qui est bien égal à d’après
l’hypothèse de récurrence. Ainsi, la correction de l’algorithme est prouvée.
Il ne reste plus qu’à déterminer la complexité de l’algorithme. On remarque qu’à chaque ité-
ration, cmpt est divisé par deux jusqu’à ce qu’il soit inférieur ou égal à 1. Comme initialement il
vaut , on en déduit qu’on fait au plus itérations. Ceci prouve donc le résultat annoncé.
d. Maintenant que vous êtes persuadés que cet algorithme fait bien ce qui était attendu, testez-le
dans votre méthode main.
1.3 Aspects pratiques de la complexité
e. Ajoutez un compteur dans chacune des fonctions myPow1 et myPow2 qui compte le nombre
d’opérations arithmétiques et de comparaisons effectuées par vos fonctions. Ainsi, ces fonctions
retourneront un tableau de deux entiers contenant le résultat de l’algorithme et le nombre d’opé-
rations qu’il a dû faire pour cela. Calculez avec chacune des fonctions pour = 10, 20, 30, 40,
50. Comparez le nombre d’opérations faites par chaque fonction et tirez-en les conclusions qui
s’imposent.
2 Recherches dans un tableau
Le but de cette section est de comparer l’efficacité des algorithmes de recherche séquentielle
et dichotomique d’une valeur dans un tableau trié de nombres entiers.
2. La terminaison d’un algorithme dénote le fait que l’algorithme se termine, notamment qu’il n’est pas piégé dans
une boucle infinie.
2
2.1 Recherche séquentielle et recherche dichotomique
f. Ecrivez une fonction rechSequentielle (cf. cours) qui prend en argument un tableau d’en-
tier tab trié et un nombre entier positif n. Cette fonction renvoie la position de ns’il est trouvé
dans le tableau et renvoie -1 sinon.
g. Ecrivez maintenant une fonction rechDichotomique (cf. cours) qui prend les mêmes ar-
guments que la fonction précédente et renvoie la même valeur, mais qui se base sur l’idée de
dichotomie (diviser pour régner) pour effectuer la recherche.
h. Quelle est la complexité de ces deux fonctions?
i. Écrivez une méthode main permettant de tester vos fonctions. Cette méthode, doit créer un
tableau de 1 000 000 de nombres entiers dont chaque case tab[i] sera initalisée avec la valeur
i + i/2, ce qui permet d’obtenir un tableau trié. Vous lancerez la recherche d’un nombre ap-
partenant au tableau (par exemple 1 125000) et d’un nombre n’appartenant pas au tableau (par
exemple 1 125 002) afin de vérifier la correction de vos deux fonctions.
2.2 Temps d’exécution
j. Afin de comparer les temps d’exécution des deux fonctions, implantez la classe Time dont le
code vous est fournit ci-dessous. Cette classe possède un constructeur qui créé un objet conte-
nant la date actuelle et une fonction d’instance millisecondsFrom qui renvoie le nombre de
millisecondes séparant deux objets de type Time. Elle va nous permettre de mesurer les temps
d’exécution des recherches.
1class Time
2{
3private java.util.Date date;
4
5Time()
6{
7date = new java.util.Date();
8}
9
10 long millisecondsFrom(Time t2)
11 {
12 return (date.getTime() - t2.date.getTime());
13 }
14 }
k. Les ordinateurs que nous utilisons étant très rapides, vous créerez deux boucles for réalisant
chacune 1 000 itérations. Dans la première, vous lancerez la recherche séquentielle d’une valeur,
et dans la seconde, vous lancerez la recherche dichotomique de la même valeur (afin que les tests
soient équitables).
Afin de mesurer le temps d’exécution de chaque boucle, vous créerez un objet de type Time
avant et après la boucle, et vous mesurerez le nombre de millisecondes qui les sépare en appelant
la fonction millisecondsFrom.
l. Comparez les temps d’exécution des 1 000 recherches séquentielles et dichotomiques.
2.3 Nombre d’opérations réalisées
m. De la même manière que pour le premier exercice, rajoutez un compteur permettant d’éva-
luer le nombre de comparaisons effectuées par chaque méthode.
3
1 / 3 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

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