TP : Divisibilité et nombres premiers 1 Récupération du matériel

publicité
Univ. Lille 1 - Licence STS 1ère année
2011-2012
Initiation à la programmation
TP : Divisibilité et nombres premiers
Objectifs du TP
Ce TP a pour but de vous faire manipuler la notion de fonction en Caml. Le
thème du TP est la divisibilité et les nombres premiers. En n de TP vous utiliserez le logiciel
1 qui permet de visualiser des données numériques sous forme de graphiques.
Gnuplot
Matériel fourni
1
Vous travaillerez à partir du chier premier-squelette.ml.
Récupération du matériel
Question 1 Récupérez le chier premier-squelette.ml et enregistrez-le dans votre dossier personnel
sous le nom premier0.ml.
Question 2 À l'aide de votre éditeur de texte favori, complétez le commentaire du début du chier
premier0.ml en précisant votre nom (ou les noms du binôme si vous travaillez à deux) et la date.
2
La fonction
est_divisible_par
Question 3 Faîtes une copie du chier premier0.ml dans un autre chier nommé premier1.ml.
Question 4 Ouvrez ce chier dans votre éditeur de texte favori, retirer le commentaire dans la
cinquième ligne ci-dessous
(* est_divisible_par : int * int
(* est_divisible_par(n,p) = VRAI
(*
FAUX
(* CU : p 6= 0
let est_divisible_par(n,p) = ((*
-> bool
*)
si p divise n *)
sinon
*)
*)
a completer *))
puis complétez cette fonction estDivisiblePar par le code qui convient pour en faire une fonction
booléenne qui teste la divisibilité de son premier paramètre par le second.
Question 5 Vériez en chargeant les déclarations du chier premier1.ml que la fonction est_divisible_par
est bien du type spécié.
# #use "premier1.ml" ;;
val est_divisible_par : int * int -> bool = <fun>
val est_premier : ’a -> unit = <fun>
- : unit = ()
Puis vériez sur plusieurs exemples que cette fonction donne bien les bonnes réponses.
1.
Gnuplot
est un logiciel libre. Pour plus d'information voir le site
1
http://www.gnuplot.info/
#
#
#
#
est_divisible_par
est_divisible_par
est_divisible_par
est_divisible_par
(5,2) ;;
(6,2) ;;
(7*123,123) ;;
(7*123 + 1,123) ;;
Question 6 Remplacez les deux dernières lignes du chier premier1.ml
let _ =
((* a completer *))
par la déclaration d'une procédure à deux paramètres de type int n et p qui imprime un message
indiquant si le premier paramètre est divisible par le second ou non. Par exemple si la procédure est
nommé etudier_divisibilite, on ddoit obtenir
#
5
#
6
-
etudier_divisibilite (5,2) ;;
n’est pas divisible par 2
: unit = ()
etudier_divisibilite (6,2) ;;
est divisible par 2
: unit = ()
Question 7 Chargez la nouvelle version du chier premier1.ml dans l'interpréteur et testez votre procédure
pour plusieurs valeurs des paramètres.
3
La fonction
est_premier
Question 8 Faites une copie du chier premier1.ml dans un autre chier nommé premier2.ml.
Rappel :
Tous les nombres entiers strictement positifs sont divisibles par 1 et par eux mêmes.
Certains ne sont divisibles que par 1 et eux-mêmes, ce sont les nombres premiers.
Il y a une innité de nombres premiers, le plus petit d'entre eux étant 2, qui est aussi le seul
nombre premier pair.
Le but de cette partie est de réaliser un test de primalité, c'est-à-dire une fonction booléenne
qui teste si l'entier qu'on lui soumet est un nombre premier ou non.
Un algorithme simple pour déterminer si un entier n au moins égal à deux est premier consiste
à rechercher le plus petit nombre supérieur à 1 qui le divise. Si ce diviseur est égal à n alors c'est
que n ne possède que deux diviseurs, et dans le cas contraire n possède (au moins) un troisième
diviseur compris entre 2 et n, et n'est donc pas premier.
En fait,√on peut démontrer que si un entier n n'est pas premier, il possède un diviseur compris
entre 2 et √ n, et on peut donc améliorer cet algorithme en arrêtant la recherche d'un plus petit
diviseur à n plutôt que n ce qui accélère le test.
Question 9 Ouvrez le chier premier2.ml dans votre éditeur de texte préféré et remplacez le commentaire dans la cinquième ligne ci-dessous
(* est_premier: int -> bool
*)
(* est_premier(n) = VRAI si n est premier *)
(*
FAUX sinon
*)
(* CU : n ≥ 0
*)
2
Algorithme 0.1 Test de primalité
Entrée : n ≥ 2 un entier.
Sortie : Vrai si n est premier, Faux sinon.
1:
2:
3:
4:
5:
k := 2
tant que k ≤ n et k ne divise pas n faire
k := k + 1
n tant que
renvoyer (k = n)
let est_premier(n) =
((* a completer *))
par le code correspondant à l'algorithme décrit ci-dessus. Attention cet algorithme ne s'applique qu'aux
entiers au moins égaux à 2. Pour les entiers plus petits (0 et 1) la réponse est immédiate.
Remarque : Il est plus simple dans un premier temps de ne pas√tenir compte de l'amélioration
suggérée en arrêtant la recherche du plus petit diviseur à n plutôt qu'à n. Si vous voulez tenir compte
de cette amélioration, compte-tenu
qu'il n'y a pas de fonction racine carrée sur les entiers en Caml, il
√
faut remplacer la condition k ≤ n par la condition équivalente k2 ≤ n.
Question 10 Chargez le chier premier2.ml dans un interpréteur et vériez le bon type de la fonction
est_premier, puis vériez son bon fonctionnement sur plusieurs exemples (cf la table de nombres premiers
donnée en annexe 6).
Question 11 À la n du chier premier2.ml remplacez la procédure etudier_divisibilite par une
procédure etudier_primalite qui imprime la primalité ou la non primalité de l'entier qu'on lui fournit
en paramètre.
Par exemple, on doit avoir les impressions
#
#
-
etudier_primalite (5) ;;
: bool = true
etudier_primalite (6) ;;
: bool = false
Question 12 Testez votre procédure avec tous les entiers de 0 à 10.
4
Détermination de tous les entiers premiers
On va maintenant produire la liste de tous les nombres premiers jusqu'à une certaine valeur
maximale
Question 13 Faites une copie du chier premier2.ml dans un autre chier nommé premier3.ml.
Question 14 Réalisez une procédure à un paramètre entier qui imprime tous les nombres premiers
inférieurs ou égaux à cet entier, à raison d'un nombre par ligne.
Question 15 Testez votre procédure, en comparant avec la table 1.
3
5
Évolution du nombre de nombres premiers
On va maintenant calculer le nombre de nombres premiers inférieurs ou égaux à une valeur
donnée.
Question 16 Faites une copie du chier premier3.ml dans un autre chier nommé premier4.ml.
Question 17 Réalisez une procédure à un paramètre entier qui imprime deux entiers par ligne, le
second étant le nombre de nombres premiers inféreurs ou égaux au premier, et ceci pour tous les entiers
compris entre 0 et l'entier passé en paramètre.
Pour un paramètre valant 100, l'achage aura la forme
0 0
1 0
2 1
3 2
4 2
5 3
...
100 25
Question 18 Donnez la valeur 1000 au paramètre.
Quel est le nombre de nombres premiers inférieurs à 1000 ? à 500 ?
Question 19 On va rediriger l'achage du votre programme dans un chier nommé premier4.1000.
Pour cela, commencez par récupérer les chiers redirection.cmi et redirection.cmo (ces deux chiers
conviennent pour la version 3.10 d'Objective Caml. Pour la version 3.11, il faut prendre ce chier.).
Puis (re)lancez l'interprète ocaml en ajoutant redirection.cmo à la ligne de commande
> ocaml redirection.cmo
Pour commencer la redirection, il sut d'ajouter avant la déclaration de votre procédure d'impression les trois lignes
open Redirection
let _ =
canal := open_out("premier4.1000")
et après cette déclaration les trois lignes
let _ =
close_out(!canal) ;
canal:=stdout
Question 20 Quelle est la taille du chier premier4.1000 obtenu avec la commande précédente ?
Question 21 Ouvrez ce chier avec votre éditeur de texte préféré. Quel est le nombre de nombres
premiers inférieurs à 500 ?
Question 22 Vous allez maintenant visualiser l'évolution du nombre de nombre premiers avec un outil
graphique nommé Gnuplot.
4
Pour cela
1. dans un terminal, tapez la commande
> gnuplot
Si tout se passe bien vous devez obtenir l'invite
gnuplot>
2. tapez maintenant la commande
gnuplot> plot "premier4.1000" with lines
Si tout se passe bien vous devez voir apparaître une fenêtre avec un graphique construit à partir des
données du chier premier4.1000 ;
3. pour quitter Gnuplot, tapez la commande
gnuplot> quit
6
Table de nombres premiers
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
101
103
107
109
113
127
131
137
139
149
151
157
163
167
173
179
181
191
193
197
199
211
223
227
229
233
239
241
251
257
263
269
271
277
281
283
293
307
311
313
317
331
337
347
349
353
359
367
373
379
383
389
397
401
409
419
421
431
433
439
443
449
457
461
463
467
479
487
491
499
503
509
521
523
541
547
557
563
569
571
577
587
593
599
601
607
613
617
619
631
641
643
647
653
659
661
673
677
683
691
701
709
719
727
733
739
743
751
757
761
769
773
787
797
809
811
821
823
827
829
839
853
857
859
863
877
881
883
887
907
911
919
929
937
941
947
953
967
971
977
983
991
997
Table 1 Table des nombres premiers inférieurs à 1000.
5
Téléchargement