TP2: Fonctions Récursives
Le fichier à remplir est ici. N’oubliez pas de tester qu’il compile avant de le mettre sur Moodle.
1 Pair et impair
Définir récursivement les fonctions pair
et impair
. On suppose que
l'argument de ces fonctions est positif ou nul. Vous ne devez pas
effectuer de division par 2, mais utiliser la fonction prédéfinie
prédécesseur pred
.
val pair : int -> bool = <fun> val impair : int -> bool = <fun>
2 Variations sur Σ
Définir une fonction
sigma
qui reçoit en argument un intervalle \([a,b]\) d'entiers représenté par un doublet et rend la somme des entiers appartenant à l'intervalle. Renvoyer \(0\) si \(a > b\).val sigma : int * int -> int = <fun>
Définir une fonction
sigma2
qui reçoit en argument une fonctionf
, un intervalle \([a,b]\) d'entiers représenté par une paire, et rend la somme des valeurs de la fonction pour chaque entier appartenant à l'intervalle.\[sigma2\;f\;[a,b] \quad = \quad \sum_{n=a}^b f(n)\]
val sigma2 : (int -> int) -> int * int -> int = <fun>
Nous allons maintenant généraliser. Plutôt que de choisir un intervalle nous allons donner une valeur de départ, une valeur de fin (pas forcément atteinte exactement, on continue tant que l'on est inférieur ou égal à cette valeur) et une valeur d'incrément. Plutôt que de faire une somme, nous allons utiliser une fonction de cumul
fc
et une valeur initiale pour le cumulacci
. Définir cette nouvelle fonctionsigma3
dont le type inféré estval sigma3 : (int -> 'a) -> int * int * int -> ('a -> 'b -> 'b) * 'b -> 'b = <fun>
et dont la sémantique est spécifiée par : \[ sigma3\;f\;(a,b,i)\;(fc,acci) \; = \; fc \; (f\; (a+n*i)) \; (\cdots fc \; (f (a+i))\; (fc\; (f a)\; acci) \cdots) \] ou de manière graphique :
Tester avec cette application qui accumule les résultats dans une liste:
let res = sigma3 (fun x -> x * x) (0,10,2) ((fun x acc -> x :: acc), [])
val res : int list = [100; 64; 36; 16; 4; 0]
Plus général encore : la fonction précédente ne permet pas de cumuler des valeurs quelconques. Plutôt que de fournir une valeur d'incrément nous allons fournir une fonction, et plutôt qu'une valeur de fin un prédicat d'arrêt. Définir donc la fonction
sigma4
val sigma4 : ('a -> 'b) -> ('a -> bool) * ('a -> 'a) -> ('b -> 'c -> 'c) * 'c -> 'a -> 'c = <fun>
utilisée comme suit
sigma4 f (predarret, fctincr) (fc,acci) a
en commençant par
a
, tant quepredarret
retourne faux, appliquerf
àa
et accumuler le résultat dansacci
avecfc
. Continuer ensuite avec la valeur suivante, donnée parfctincr
appliquée àa
.Utiliser
sigma4
pour définir une fonction de cumulcum
sur un intervalle flottant \([a,b]\) avec un pas \(dx\).val cum : (float -> 'a) -> float * float * float -> ('a -> 'b -> 'b) * 'b -> 'b = <fun>
Utiliser
cum
pour définir une fonctionintegre
d'intégration numérique sachant : \[\int_a^b f(x) dx \quad \approx \quad \sum_{n=0}^{n=\lfloor \frac{b-a}{dx} \rfloor} f(a+n dx)dx\]val integre : (float -> float) -> float * float * float -> float = <fun>
Utiliser
integre
pour approcher \(\int_1^2 \frac{1}{x}dx\).
3 Recherche du maximum d'une fonction
Considérons une fonction continue \(f\) ayant un maximum local unique sur l'intervalle \([a,b]\) et n'étant jamais constante sur un sous-intervalle de \([a,b]\). Nous nous intéressons au calcul du maximum de cette fonction sur l'intervalle \([a,b]\) . La méthode s'appuie sur l'idée suivante : soient \(x\) et \(y\) deux points de l'intervalle \([a,b]\) tels que \(x < y\). Si \(f(x) > f(y)\) alors le maximum se situe dans l'intervalle \([a,y]\), tandis que si \(f(x) < f(y)\) le maximum est dans l'intervalle \([x,b]\). Définir une fonction maxi
qui reçoit en argument une fonction \(f\), un intervalle \([a,b]\) et une précision \(p\) et calcule le maximum \(f\; m\) de \(f\) sur cet intervalle \([a,b]\) de telle sorte que \(m\) soit déterminé avec une précision \(p\). Attention, il faut retourner \(f\;m\) et pas \(m\). Penser aux définitions locales et tester.
val maxi : (float -> 'a) -> float * float -> float -> 'a = <fun>
4 Pour aller plus loin… Calcul de \(\pi\) avec la méthode de Monte Carlo
Si l'on suppose que le générateur aléatoire de OCaml est uniforme et que l'on fait deux tirages aléatoires x
et y
entre 0.
et 1.
, alors la probabilité que \(x^2 + y^2 \leq 1\) est égale à \(\pi / 4\). Intuitivement, x
et y
représentent un point dans un carré de côté \(1\), et si \(x^2 + y^2 \leq 1\), alors le point est dans le quart de disque centré en \((0,0)\) et de rayon \(1\).
Écrire une fonction montepi n
qui tire n
points au hasard et donne une approximation de \(\pi\). On pourra se servir le la fonction Random.float f
qui retourne un nombre flottant au hasard compris entre 0.
et f
.
val montepi : int -> float = <fun>
let pi = montepi 1000000
val pi : float = 3.14254