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