3MMALG11 Soutien S01

De Ensiwiki
Aller à : navigation, rechercher
AttentionCette page est maintenue uniquement par les enseignants. Afin de ne pas perturber le déroulement des cours, elle n'a pas vocation à être modifiée par les élèves. Mais si vous avez des modifications à proposer, merci d'en discuter ou d'envoyer un e-mail aux auteurs de la page (cf. historique)


Affichage de suites

Le but de cet exercice est de travailler sur des itérations très simples pour commencer.

Factorielle

Commencez par compléter le programme ci-dessous en implantant la fonction Fact qui calcule la factorielle de l'entier naturel passé en paramètre. On demande une implantation itérative (et pas récursive) pour la fonction Fact.

On rappelle que factorielle est définie par  :

  • Fact(0) = 1
  • Fact(N) = N * Fact(N-1)
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;

procedure S01_E1 is

    function Fact(N: Natural) return Positive is
    ...

    N: Natural;

begin
    Put("Entrer un naturel : "); Get(N);
    Put("Fact("); Put(N, Width=>0); Put(") = ");
    Put(Fact(N), Width=>0); New_Line;
end S01_E1;

Il est important de rappeler que les noms des fichiers contenant des programmes Ada doivent être complètement en minuscules. Ici, vous appellerez votre fichier s01_e1.adb.

Modifiez ensuite le programme principal pour qu'il n'affiche non plus seulement Fact(N) mais la suite des valeurs de Fact(I) pour tous les I entre 0 et N inclus.

Fibonacci

Reprendre le même exercice pour la suite de Fibonacci : commencer par implanter une fonction calculant Fibo(N) pour un N donné, puis ajouter une boucle pour afficher la suite de toutes les valeurs de la suite de Fibonacci pour I allant de 0 à N inclus.

On rappelle que la suite de Fibonacci est définie par :

  • Fibo(0) = 1
  • Fibo(1) = 1
  • Fibo(N) = Fibo(N-2) + Fibo(N-1)

Analyse d'une suite d'entiers

Le but de cet exercice est d'écrire un premier module (package) simple et d'apprendre à l'utiliser comme une boite noire.

Spécification du module

Lorsqu'on demande d'écrire un module, on donne toujours sa spécification sous la forme de son interface. L'interface est le "contrat" qui liste les actions fournies par le module et comment on doit les utiliser.

Ici, on donne l'interface suivante pour le module SuiteEntiers :

package SuiteEntiers is
   --  Initialise le module et entre le premier entier
   procedure Init(X: Integer);
   --  Entre un nouvel entier
   procedure Entre(X: Integer);
   --  Renvoie le nombre d'entiers entrés
   function NbEntrees return Natural;
   --  Renvoie la somme des entiers entrés
   function Somme return Natural;
   --  Renvoie l'entier maximum parmi ceux entrés
   function Maximum return Natural;
   --  Renvoie vrai ssi la suite des entiers
   --    entrées est strictement croissante
   --    On considere par convention que la suite vide
   --      n'est pas croissante
   function EstCroissante return Boolean;
end SuiteEntiers;

Recopiez cette interface dans un fichier appelé forcément suiteentiers.ads (il est important d'écrire les noms de fichiers tout en minuscules).

Programme principal

Une fois qu'on a l'interface d'un module, on peut l'utiliser même sans savoir comment il est implanté. On va donc écrire le programme principal utilisant le module SuiteEntiers avant d'implanter les procédures qui le compose.

Complétez le programme principal ci-dessous en écrivant une boucle qui lit des entiers, les enregistre dans le module (en utilisant Init pour le premier et Entre pour les suivants) et s'arrête dès qu'on saisit un entier négatif :

with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Float_Text_IO, SuiteEntiers;
use Ada.Text_IO, Ada.Integer_Text_IO, Ada.Float_Text_IO, SuiteEntiers;

procedure S01_E2 is

    X: Integer;

begin
    Put_Line("Entrer les entiers positifs :");
    ...
    if (NbEntrees > 0) then
        Put("Moyenne = ");
        Put(Float(Somme) / Float(NbEntrees), Aft => 0, Exp => 0);
        New_Line;
    end if;
    Put("Maximum = "); Put(Maximum, Width => 0); New_Line;
    Put_Line("Suite croissante : " & Boolean'Image(EstCroissante));
end S01_E2;

On voit que le programme principal va utiliser les procédures du module pour afficher des statistiques sur les données entrées, une fois la boucle terminée.

Implantation du module

On va finalement implanter le module SuiteEntiers. Pour cela, on peut se représenter le module comme une machine à état simple, composée :

  • de variables globales, dont l'ensemble constitue l'état de la machine ;
  • de fonctions de sélection, dont le rôle est juste de renvoyer la valeur de telle ou telle variable de l'état global (et notamment pas de modifier cet état) ;
  • de procédures de mise à jour de l'état, qui vont influer sur les variables globales du module.

Dans le cadre de cet exercice, les procédures de mise à jour sont Init et Entre, et toutes les autres primitives à implanter sont des fonctions de sélection.

Vous devez donc compléter le corps du module SuiteEntiers que l'on donne ci-dessous :

package body SuiteEntiers is

    Nb: Natural;

    procedure Init(X: Integer) is
    begin
        Nb := 1;
        ...
    end Init;

    procedure Entre(X: Integer) is
    begin
        Nb := Nb + 1;
        ...
    end Entre;

    function NbEntrees return Natural is
    begin
        return Nb;
    end NbEntrees;

    function Somme return Natural is
    ...

    function Maximum return Natural is
    ...

    function EstCroissante return Boolean is
    ...

end SuiteEntiers;

On a implanté la fonction NbEntrees comme exemple de ce qu'il faut faire : on note bien qu'elle ne fait que renvoyer la valeur de la variable globale (privée, c'est à dire interne) Nb sans la modifier : ce sont les procédures de mise à jour Init et Entre qui modifient cette variable.

Vous devez compléter le corps du module, en implantant les fonctions restantes. Pour cela, vous devrez à chaque fois :

  • définir une ou plusieurs variables globales pour intégrer dans l'état du module les informations nécessaires à la fonction implantée ;
  • modifier Init et Entre pour mettre à jour l'état du module en fonction des valeurs entrées ;
  • implanter la fonction de sélection voulue, qui ne doit faire que renvoyer la valeur de la variable interne correspondant à son rôle.

Vous testerez vos fonctions au fur et à mesure de leur développement (pas toutes d'un coup à la fin !). Pour cela, il suffit de mettre en commentaire dans le programme principal les appels aux fonctions non-implantées, et de les décommenter au fur et à mesure.