TP 3 : Fonctions arithmétiques récursives

publicité
L1-S1-IMP
Informatique
Année 2010 - 2011
Semestre 1
TP 3 : Fonctions arithmétiques récursives
1
Plus Petit Commun Multiple
Exercice 1 Écrire une fonction ppcm qui calcule le plus petit multiple commun de deux entiers positifs.
Si les entiers ne sont pas tous les deux positifs, ppcm devra renvoyer la valeur 0.
Indication : soit la paire d’entiers (a, b). Examinons, dans l’ordre croissant, les multiples successifs de
a (a, 2a, 3a, . . . ) jusqu’à ce qu’on en trouve un qui soit divisible par b : ce nombre est, par définition, le
P.P.C.M. de a et de b. La recherche est accélérée si a est supérieur à b.
Exemples d’application de la fonction ppcm :
# ppcm(12,28) ;;
- : int = 84
# ppcm(58,28) ;;
- : int = 812
# ppcm(10,21) ;;
- : int = 210
# ppcm(-14,28) ;;
- : int = 0
Astuce : Vous pouvez tracer l’exécution d’une fonction. Pour la fonction ppcm, faites :
# #trace ppcm ;;
Ensuite, vous pouvez exécuter la fonction comme d’habitude. Pour vous débarrasser de la trace, faites :
# #untrace ppcm ;;
Dans les deux cas, il y a deux #, dont le premier est l’invite de Caml et le deuxième appartient à la
commande trace/untrace.
2
Nombres premiers
Exercice 2 Écrire une fonction sigma qui calcule la somme des diviseurs d’un entier n positif ou nul.
Si n est négatif on conviendra que sigma(n) = 0. Indication : on suggère d’écrire une fonction auxiliaire
récursive qui calcule la somme des diviseurs de n compris entre k et n, k étant un entier inférieur ou égal
à n. Après avoir écrit une version simple de cette fonction auxiliaire, on pourra envisager de l’améliorer
en optimisant la recherche des diviseurs de n.
Exemples d’application de la fonction sigma :
# sigma 1 ;;
- : int = 1
# sigma 30 ;;
- : int = 72
# sigma 31 ;;
- : int = 32
# sigma 49 ;;
- : int = 57
# sigma (-1) ;;
- : int = 0
Rappel : par définition, un entier naturel n est premier s’il a exactement deux diviseurs (1 et n). Le
plus petit nombre premier est 2 (1 n’a qu’un seul diviseur . . .).
Exercice 3 Écrire une fonction est premier qui détermine si un entier est premier ou pas. Pour décider
si un nombre est premier on se servira de la fonction sigma écrite précédemment.
Exemples d’application de la fonction est premier :
# est_premier 1 ;;
- : bool = false
# est_premier 30 ;;
- : bool = false
# est_premier 31 ;;
- : bool = true
# est_premier (-5);;
- : bool = false
Exercice 4 Écrire une fonction récursive prochain premier qui, étant donné un entier n quelconque
renvoie le plus petit nombre premier strictement supérieur à n.
Exemples d’application de la fonction prochain premier :
L1-S1 Info 2010 - 2011
1
TP3
# prochain_premier 0 ;;
- : int = 2
# prochain_premier 7 ;;
- : int = 11
# prochain_premier 523 ;;
- : int = 541
Exercice 5 Écrire une fonction keme premier qui, étant donné un entier k > 0, retourne le kème nombre
premier (2 est le 1er nombre premier, 3 le 2ème, etc.). Si k est négatif ou nul, c’est une erreur. Indication :
ici aussi, on suggère d’écrire une fonction auxiliaire récursive qui, étant donné deux entiers n et k, recherche
le kème nombre premier au-delà de n (supérieur à n).
Exemples d’application de la fonction keme premier :
# keme_premier 1;;
- : int = 2
3
# keme_premier 2;;
- : int = 3
# keme_premier 100;;
- : int = 541
# keme_premier 1000;;
- : int = 7919
Autour de la dichotomie
3.1
Calcul de la racine carrée
Exercice (à préparer) 6 Concevoir une fonction racine carree qui calcule, en utilisant le principe de
la dichotomie, une valeur approchée par défaut, à près, de la racine carrée d’un nombre x (x et sont
les données du problème).
Indications : on suggère de prendre comme espace de recherche initial l’intervalle [1, x] si x > 1 et
[x, 1] si x < 1. À chaque étape de la dichotomie, l’espace de recherche sera partagé en deux parties égales
(2 intervalles de même taille).
Vous devez préparer la solution à l’avance, puis l’implanter et la tester en séance de TP.
Votre solution:
Exemples d’application de la fonction racine carree :
#
#
-
racine_carree(16.,1e-5) ;;
: float = 3.9999971389770508
racine_carree(2.,1e-4) ;;
: float = 1.4141845703125
3.2
#
#
-
racine_carree(2.,1e-15) ;;
: float = 1.4142135623730949
racine_carree(1024.,1e-10) ;;
: float = 31.999999999971806
Amélioration de la racine carrée
Faites évaluer racine carree(2.,1e-16). Que constate-t-on ? En vous appuyant sur ce que vous
savez sur la représentation des nombres en virgule flottante, vous allez modifier la fonction précédente
pour que la recherche s’arrête lorsque la précision maximum est atteinte.
Exercice 7 Écrire une fonction racine 2 qui calcule la racine carrée d’un nombre x avec la meilleure
précision possible (il n’y a plus qu’une seule donnée : x).
Exemples d’application de racines 2 :
# racine_2 2. ;;
- : float = 1.4142135623730949
L1-S1 Info 2010 - 2011
# racine_2 1024. ;;
- : float = 32.
2
# racine_2 0.25 ;;
- : float = 0.5
TP3
4
Pavages
En cours, vous avez vu le problème du dénombrement des pavages d’un couloir avec deux sortes de
carreaux. Nous rappelons ici la fonction paver qui résout le problème :
let rec
1 ->
| 2 ->
| n ->
paver = function
1
2
paver (n-1) + paver (n-2);;
La fonction paver calcule le nombre de pavages, mais ne les affiche pas directement.
Exercice (à préparer) 8 Développez l’arbre d’exécution de paver 5.
Généralisez le résultat et donnez une borne inférieure pour le nombre d’appels récursifs pour calculer
paver n, pour n ≥ 2.
Votre solution:
Exercice 9 Mesurez le temps d’exécution de la fonction paver n pour quelques valeurs représentatives.
Voici comment faire, pour n = 30 :
# let t1 = Sys.time () in
let _ = paver 30 in
let t2 = Sys.time () in t2 -. t1 ;;
- : float = 0.160000000000003695
Il peut être instructif de choisir, par exemple, n = 35 et n = 40.
Que constatez-vous ? Comparez avec vos résultats de l’exercice 8.
Exercice 10 Nous essayons de rendre l’exécution de la fonction considérablement plus efficace, en utilisant une technique connue comme mémoization.
Pour cela, nous définissons une fonction paver aux n dont le but est de calculer le couple des valeurs
(paver n, paver (n − 1)), mais de manière efficace. Pour le cas n = 1, on choisit (1, 0) :
let rec
1 ->
| 2 ->
| n ->
paver_aux = function
(1, 0)
(2, 1)
....
Complétez le cas récursif de la définition (bien sûr, sans faire appel à paver). Définissez la fonction
paver lin à l’aide de paver aux, qui renvoie la première composante du résultat de paver aux et qui est
fonctionnellement équivalente à paver :
# paver_lin 6 ;;
- : int = 13
Testez l’équivalence avec quelques exemples !
Quel est le nombre d’appels récursifs de paver aux n, pour n ≥ 2 ?
Mesurez le temps d’exécution de paver lin, comme vu dans l’exercice 9.
L1-S1 Info 2010 - 2011
3
TP3
Téléchargement