• Aucun résultat trouvé

Un exemple très… mathématique

Dans le document Apprenez à programmer avec Ada (Page 105-109)

Ce troisième et dernier exemple s'adresse à ceux qui ont des connaissances mathématiques un peu plus poussées (disons, niveau terminale scientifique). En effet, les fonctions sont un outil mathématique très puissant et très courant. Et deux opérations essentielles peuvent-être appliquées aux fonctions : la dérivation et l'intégration. Je souhaiterais traiter ici l'intégration. Ou plutôt, une approximation de l'intégrale d'une fonction par la méthode des trapèzes.

Pour rappel, et sans refaire un cours de Maths, l'intégrale entre a et b d'une fonction f correspond à l'aire comprise entre la courbe représentative de la fonction (entre a et b) et l'axe des abscisses. Pour approximer cette aire, plusieurs méthodes furent inventées, notamment la méthode des rectangles qui consiste à approcher l'aire de cette surface par une série de rectangles. La méthode des trapèzes consiste quant à elle à l'approximer par une série de trapèzes rectangles.

Graphique de la fonction f

Dans l'exemple précédent, on a cherché l'aire sous la courbe entre 1 et 4. L'intervalle [ 1 ; 4 ] a été partagé en 3 sous-intervalles de longueur 1. La longueur de ces sous-intervalles est appelée le pas. Comment calculer l'aire du trapèze ABB'A' ? De la manière

suivante : . Et on remarquera que , ,

...

Nous allons donc définir quelques fonctions dont voici les prototypes : Code : Ada

function carre(x : float) return float ; function cube(x : float) return float ; function inverse(x : float) return float ;

Nous allons également définir un type T_Pointeur : Code : Ada

type T_Pointeur is access function(x : float) return float ;

Nous aurons besoin d'une fonction Aire_Trapeze et d'une fonction Integrale dont voici les prototypes : Code : Ada

--aire_trapeze() ne calcule l'aire que d'un seul trapèze --f est la fonction étudiée

--x le "point de départ" du trapèze

--pas correspond au pas, du coup, x+pas est le "point d'arrivée" du trapèze

function aire_trapeze(f : T_Pointeur ; x : float ; pas : float) return float ;

--integrale() effectue la somme des aires de tous les trapèzes ainsi que le calcul du pas

--f est la fonction étudiée --min et max sont les bornes

--nb_inter est le nombre de sous-intervalles et donc de trapèzes, --ce qui correspond également à la précision de la mesure function integrale(f: T_pointeur ;

min,max: float ;

nb_inter : integer) return float is

Je vous laisse le soin de rédiger seuls ces deux fonctions. Cela constituera un excellent exercice sur les pointeurs mais aussi sur les intervalles et le pas. Il ne reste donc plus qu'à appeler notre fonction integrale( ) :

Code : Ada

--a,b sont des float saisis par l'utilisateur représentant les bornes de l'intervalle d'intégration

--i est un integer saisi par l'utilisateur représentant le nombre de trapèzes souhaités

integrale(carre'access,a,b,i) ; integrale(cube'access,a,b,i) ; integrale(inverse'access,a,b,i) ;

Bon allez ! Je suis bon joueur, je vous transmets tout de même un code source possible. Attention, ce code est très rudimentaire, il ne teste pas si la borne inférieure est bel et bien inférieure à la borne supérieure, rien n'est vérifié quant à la continuité ou au signe de la fonction étudiée… bref, il est éminemment perfectible pour un usage mathématique régulier. Mais là, pas la peine d'insister, vous le ferez vraiment tous seuls.

Secret (cliquez pour afficher) Code : Ada

with ada.Text_IO, ada.Integer_Text_IO, ada.Float_Text_IO ; use ada.Text_IO, ada.Integer_Text_IO, ada.Float_Text_IO ; procedure integration is

Fonctions de x

function carre(x : float) return float is begin

Partie 3 : Ada, les types composites 105/312

return x**2 ;

type T_Pointeur is access function (x : float) return float ;

function integrale(f: T_pointeur ; min,max: float ; nb_inter : integer) return float is

put("Entre quelles valeurs souhaitez-vous integrer les fonctions ?") ;

get(a) ; get(b) ; skip_line ;

put("Combien de trapezes souhaitez-vous construire ?") ; get(i) ; skip_line ;

put("L'integrale de la fonction carre est : ") ; put(integrale(carre'access,a,b,i),Exp=>0) ; new_line ; put("L'integrale de la fonction inverse est : ") ; put(integrale(inverse'access,a,b,i),Exp=>0) ; new_line ; put("L'integrale de la fonction cube est : ") ; put(integrale(cube'access,a,b,i),Exp=>0) ; new_line ; end integration ;

Exercices Exercice 1

Énoncé

Voici un programme tout ce qu'il y a de plus simple : Code : Ada

Vous devez modifier ce code de façon à changer le contenu des variables n et m, sans jamais modifier les variables elles-mêmes.

Ainsi, le résultat affiché sera faux.

Solution

Reprenez l'exercice précédent en remplaçant les deux variables n et m par un tableau T de deux entiers puis, en modifiant ses valeurs uniquement à l'aide d'un pointeur.

Solution type T_Pointeur is access all T_Tableau ; T : aliased T_Tableau ;

P : T_Pointeur ; begin

Put("Choisissez un nombre n :") ; get(T(1)) ; skip_line ; Put("Choisissez un nombre m :") ; get(T(2)) ; skip_line ; P := T'access ;

P.all(1):= P.all(1)*18 ; P.all(2):= P.all(2)/2 ;

Put("La somme des nombres choisis est ") ; Put(T(1)+T(2)) ;

Partie 3 : Ada, les types composites 106/312

end programme ;

Exercice 3

Énoncé

Reprenez le premier exercice, en remplaçant les deux variables n et m par un objet de type structuré comportant deux composantes entières puis, en modifiant ses composantes uniquement à l'aide d'un pointeur.

Solution

Secret (cliquez pour afficher) Code : Ada

with ada.Text_IO, ada.Integer_Text_IO ; use ada.Text_IO, ada.Integer_Text_IO ; procedure programme is

type T_couple is record

n,m : integer ; end record ;

type T_Pointeur is access all T_couple ; Couple : aliased T_couple ; P : T_Pointeur ; begin

Put("Choisissez un nombre n :") ; get(couple.n) ; skip_line ; Put("Choisissez un nombre m :") ; get(couple.m) ; skip_line ; P := Couple'access ;

P.all.n:= P.all.n**2 ; P.all.m:= P.all.m mod 3 ; Put("La somme des nombres choisis est ") ; Put(Couple.n + Couple.m) ;

end programme ;

Il est également posible (mais je vous déconseille pour l'instant de le faire afin d'éviter toute confusion) d'écrire les lignes suivantes :

Code : Ada P.n:= P.n**2 ; P.m:= P.m mod 3 ;

C'est un «raccourci» que permet le langage Ada. Attention toutefois à ne pas confondre le pointeur P et l'objet pointé !

Exercice 4

Énoncé

Reprenez le premier exercice. La modification des deux variables n et m se fera cette fois à l'aide d'une procédure dont le(s) paramètres seront en mode IN.

Solution

Secret (cliquez pour afficher) Code : Ada

with ada.Text_IO, ada.Integer_Text_IO ; use ada.Text_IO, ada.Integer_Text_IO ; procedure programme is

procedure modif(P : access integer) is begin

P.all := P.all*5 + 8 ; end modif ;

n,m : aliased integer ; begin

Put("Choisissez un nombre n :") ; get(n) ; skip_line ; modif(n'access) ;

Put("Choisissez un nombre m :") ; get(m) ; skip_line ; modif(m'access) ;

Put("La somme des nombres choisis est ") ; Put(n+m) ;

end programme ;

Exercice 5 (Niveau Scientifique)

Énoncé

Rédigez un programme calculant le coefficient directeur de la sécante à la courbe représentative d'une fonction f en deux points A et B. À partir de là, il sera possible de réaliser une seconde fonction qui donnera une valeur approchée de la dérivée en un point de la fonction f.

Par exemple, si , alors la fonction Secante(f,2,7) renverra . La fonction Derivee(f,5) renverra quant à elle où h devra être suffisamment petit afin d'améliorer la précision du calcul.

Solution

Secret (cliquez pour afficher) Code : Ada

with ada.Text_IO, ada.Float_Text_IO, ada.Integer_Text_IO ; use ada.Text_IO, ada.Float_Text_IO, ada.Integer_Text_IO ; procedure derivation is

type T_Ptr_Fonction is access function(x : float) return float

;

function carre (x : float) return float is begin return x**2 ;

end carre ;

function cube(x : float) return float is begin return x**3 ;

end cube;

function inverse(x : float) return float is begin return 1.0/x ;

end inverse;

function secante(f : T_Ptr_Fonction ; a : float ;

b : float ) return float is begin

return (f(b)-f(a))/(b-a) ; end secante ;

function derivee(f : T_Ptr_Fonction ; x : float ;

precision : float := 0.000001) return float is

Partie 3 : Ada, les types composites 107/312

begin

return secante(f,x,x+precision) ; end derivee ;

choix : integer := 1 ; f : T_Ptr_Fonction ; x: float ; begin loop

put("Quelle fonction souhaitez-vous deriver ? Inverse(1), Carre(2) ou Cube(3) .") ;

get(choix) ; skip_line ; case choix is

when 1 => f := inverse'access ; when 2 => f := carre'access ; when 3 => f := cube'access ; when others => exit ; end case ;

put("Pour quelle valeur de x souhaitez-vous connaitre la derivee ?") ;

get(x) ; skip_line ;

put("La derivee vaut environ") ; put(derivee(f,x),Exp=>0,Aft=>3) ; put(" pour x =") ; put(x,Exp=>0,Aft=>2) ;

new_line ; new_line ; end loop ;

end derivation ;

Il est possible de demander à l'utilisateur de régler la «précision» lui-même, mais j'ai retiré cette option car elle alourdissait l'utilisation du programme sans apporter de substantiels avantages.

Bien, si vous réalisez ces exercices c'est que vous devriez être venus à bout de ces deux chapitres éprouvants. Il est fort possible que vous soyez encore assaillis de nombreuses questions. C'est pourquoi je vous conseille de pratiquer. Ce cours vous a proposé de nombreux exercices, il n'est peut-être pas inutile de reprendre des exercices déjà faits (affichage de tableau, de rectangles…) et de les retravailler à l'aide des pointeurs car cette notion est réellement compliquée. N'hésitez pas non plus à relire le cours à tête reposée.

Si d'aventure vous pensez maîtriser les pointeurs, alors un véritable test vous attend au chapitre 10. Nous mettrons les pointeurs en pratique en créant avec nos petites mains un nouveau type de donnée et les outils pour le manipuler : les types abstraits de donnée ! Là encore, ce sera un chapitre complexe, mêlant théorie et pratique. Mais avant cela nous allons aborder une notion difficile également : la récursivité.

En résumé :

Si vous souhaitez que votre pointeur puisse également pointer sur des variables et donc sur de la mémoire statique, vous devrez le préciser lors de la déclaration du type en indiquant IS ACCESS ALL.

De la même manière, si vous souhaitez qu'une variable puisse être pointée, il faudra l'indiquer par le terme ALIASED Prenez soin de ne pas mélanger pointeur constant (où l'adresse pointée ne peut pas être modifiée, mais le contenu si) et pointeur sur une constante (où le pointeur peut être modifié à condition qu'il pointe toujours sur une constante).

Le passage en paramètre d'un pointeur à une fonction permet d'avoir accès aux données pointées en lecture comme en écriture. Un paramètre en mode ACCESS est équivalent à un paramètre en mode IN OUT.

Il est également possible de déclarer des pointeurs sur des fonctions ou des procédures. Mais vous devez faire attention au nombre, au type et au mode des paramètres (ou du résultat) lorsque vous déclarez le type pointeur.

Partie 3 : Ada, les types composites 108/312

Dans le document Apprenez à programmer avec Ada (Page 105-109)