• Aucun résultat trouvé

La calculatrice : Comment faire faire (à un premier niveau) ?

3 Les limites de l'approche descendante

1. Une calculatrice pour le grand Jules

1.4 La calculatrice : Comment faire faire (à un premier niveau) ?

Il nous reste à mettre en oeuvre dans un choix de variables et dans l'écriture d'une marche à suivre la stratégie retenue.

1.4.1 Structure de données.

1.4.1.1 Constantes inhérentes au problème.

A ce niveau de l'analyse, la seule constante qu'on pourrait éventuellement mettre au jour est la taille maximale des chaînes de caractères qui constitueront les nombres romains. Ce n'est certes pas une constante importante pour la compréhension du problème.

1.4.1.2 Types

Comme Pascal nous le permettra, nous définirons le type NombreRomain comme synonyme de string[40]. Autrement dit, les nombres romains manipulés seront toujours des chaînes d'au plus 40 caractères.

On verra dans la suite que cette définition d'un type, qui paraît assez facultative, s'avérera indispensable, pour des raisons qui tiennent à la syntaxe exigée par Pascal.

1.4.1.3 Les tableaux nécessaires

Il n'y en a aucun à ce niveau de l'analyse.

A nouveau, il ne faut pas anticiper sur les actions (complexes !) qui resteront à analyser : où nous en sommes, aucun tableau n'est indispensable.

1.4.2 Marche à suivre

AVERTIR Répéter

Lis PremierNombreRomain PremierNombreRomain de type NombreRomain

Lis SecondNombreRomain SecondNombreRomain de type NombreRomain

DECIMALISER_PREMIERNOMBREROMAIN_EN_PREMIERNOMBREDECIMAL

PremierNombreDecimal de type entier long

DECIMALISER_SECONDNOMBREROMAIN_EN_SECONDNOMBREDECIMAL

SecondNombreDecimal de type entier long SommeDecimal PremierNombreDecimal + SecondNombreDecimal SommeDecimal entier long DifferenceDecimal PremierNombreDecimal SecondNombreDecimal DifferenceDecimal entier long ProduitDecimal PremierNombreDecimal * SecondNombreDecimal ProduitDecimal entier long

ROMANISER_SOMMEDECIMAL_EN_ SOMMEROMAIN

SommeRomain de type NombreRomain

ROMANISER_ABS_DIFFERENCEDECIMAL_EN_ DIFFERENCEROMAIN

DifferenceRomain de type NombreRomain

ROMANISER_PRODUITDECIMAL_EN_ PRODUITROMAIN

ProduitRomain de type NombreRomain

Affiche SommeRomain

Si DifferenceDecimal = 0 alors Affiche "Différence nulle" sinon

Si DifferenceDecimal > 0 alors Affiche DifferenceRomain

sinon

Affiche "-" suivi de DifferenceRomain Affiche ProduitRomain

Demander à l'utilisateur s'il souhaite recommencer et lire Reponse

jusqu'à ce que Reponse= 'N' Reponse de type char

Les équivalents décimaux des nombres romains traités ont tous le type entier long. Nous savons que le type entier simple (integer) ne couvre que les nombres entiers dans l'intervalle -32768 à 32767 et que, si cela est suffisant en ce qui concerne les nombres fournis (compris entre 1 et 999) comme en ce qui concerne la somme et la différence de ceux-ci, leur produit par contre posera des problèmes puisqu'il peut atteindre 998001(soit 999 x 999). Pascal offre pour la manipulation des entiers de grande taille le type "entier long" (LongInt) qui permet la représentation d'entiers entre -2147483648 et 2147483647 (voir page 29). Même si ce n'est indispensable que dans le cas du produit, j'ai préféré, pour des motifs de simplicité et d'homogénéité, déclarer tous les entiers traités de type entier long.

En laissant de côté, les spécifications de AVERTIR (pour lesquelles il suffit de consulter le premier écran proposé), il reste à préciser :

DECIMALISER_PREMIERNOMBREROMAIN_EN_PREMIERNOMBREDECIMAL

PremierNombreRomain

de type NombreRomain

Transformer le nombre en chiffres romains

PremierNombreRomain en son équivalent décimal

et placer celui-ci dans PremierNombreDecimal

Premier NombreDecimal de type entier long avec

Avant Après

- PremierNombreRomain de type NombreRomain qui contient un nombre romain correctement écrit (entre I (1) et CMXCIX (999)).

- PremierNombreRomain ne peut avoir changé

- PremierNombreDecimal de type entier long, contient un entier entre 1 et 999 correspondant au nombre

PremierNombreRomain .

et, bien entendu :

DECIMALISER_SECONDNOMBREROMAIN_EN_SECONDNOMBREDECIMAL

SecondNombreRomain

de type NombreRomain

Transformer le nombre en chiffres romains

SecondNombreRomain en son équivalent décimal et

placer ce dernier dans SecondNombreDecimal

SecondNombreDecimal de type entier long avec

Avant Après

- SecondNombreRomain de type NombreRomain qui contient un nombre romain correctement écrit (entre I (1) et CMXCIX (999)).

- SecondNombreRomain ne peut avoir changé

- SecondNombreDecimal de type entier long, contient un entier entre 1 et 999 correspondant au nombre

SecondNombreRomain .

et

ROMANISER_SOMMEDECIMAL_EN_ SOMMEROMAIN

SommeDecimal

de type entier long

Transformer le résultat SommeDecimal en son

équivalent en chiffres romains SommeRomain SommeRomain

de type NombreRomain avec

Avant Après

- SommeDecimal de type entier long, qui contient la somme écrite sous forme décimale, toujours comprise entre 2 et 1998.

- SommeDecimal ne peut avoir changé

- SommeRomain de type NombreRomain, contenant le nombre en chiffres romains correspondant à

SommeDecimal.

ROMANISER_ABS_DIFFERENCEDECIMAL_EN_ DIFFERENCEROMAIN

DifferenceDecimal

de type entier long

Transformer la valeur absolue du résultat

DifferenceDecimal en son équivalent en chiffres romains DifferenceRomain

DifferenceRomain

de type NombreRomain avec

Avant Après

- DifferenceDecimal de type entier long, qui contient la différence écrite sous forme décimale, toujours comprise entre -998 et 998.

- DifferenceDecimal ne peut avoir changé

- DifferenceRomain de type NombreRomain, contenant le nombre en chiffres romains correspondant à la valeur absolue de DifferenceDecimal.

ROMANISER_PRODUITDECIMAL_EN_ PRODUITROMAIN

ProduitDecimal de type entier long

Transformer le résultat ProduitDecimal en son

équivalent en chiffres romains ProduitRomain ProduitRomain

de type NombreRomain avec

Avant Après - ProduitDecimal de type entier long, qui contient le produit écrit

sous forme décimale, toujours compris entre 1 et 998001 (999*999)

- ProduitDecimal ne peut avoir changé

- ProduitRomain de type NombreRomain, contenant le nombre en chiffres romains correspondant à ProduitDecimal.

On pourrait poursuivre l'analyse comme si de rien n'était avec chacune des actions complexes ainsi spécifiée. On constate cependant que les deux premières actions complexes

DECIMALISER_PREMIERNOMBREROMAIN_EN_PREMIERNOMBREDECIMAL et DECIMALISER_SECONDNOMBREROMAIN_EN_SECONDNOMBREDECIMAL constituent

la même action, appliquée la première fois à PremierNombreRomain pour remplir PremierNombre

Decimal, la seconde fois à SecondNombreRomain pour remplir SecondNombreDecimal. Il serait

donc absurde de recommencer deux fois la même analyse, les seules modifications de l'une à l'autre étant les changements du nom des variables concernées.

Ce qu'il faudrait, c'est non pas pouvoir analyser l'action permettant, sur base de telle variable

précise contenant un nombre en chiffres romains de passer à telle variable précise contenant son

équivalent décimal, mais décrire l'action qui sur base d'un nombre en chiffres romains fournisse dans une quelconque variable (de type entier long) son équivalent décimal. C'est seulement aux moments où cette action serait activée (= lors de l'appel de la procédure) qu'on préciserait à chaque fois le nombre à transformer et la variable accueillant le résultat de la transformation.

On écrirait en quelque sorte :

DECIMALISER(Romain : NombreRomain; var Decimal : entier long)

Romain

paramètre de type NombreRomain

Transformer le nombre en chiffres romains Romain en

son équivalent décimal et le placer dans Decimal Decimal

paramètre de type entier long avec

Avant Après - Romain : paramètre de type NombreRomain qui contient un

nombre romain correctement écrit (entre I (1) et CMXCIX (999)).

- Decimal : paramètre de type entier long, contient un entier entre 1 et 999 correspondant au nombre en chiffres romains

Romain .

Au moment de l'appel des procédures, au lieu d'appeler successivement deux procédures différentes, c'est la même procédure, DECIMALISER, qui serait appelée, mais en précisant à chaque fois ce que sont vraiment chacun des deux paramètres dont elle est assortie.

Ainsi, au lieu d'appeler

DECIMALISER_PREMIERNOMBREROMAIN_EN_PREMIERNOMBREDECIMAL, on appellerait DECIMALISER, en précisant, pour cette fois que

- PremierNombreRomain "remplace" Romain et

- PremierNombreDecimal "remplace" Decimal

et au lieu de

DECIMALISER_SECONDNOMBREROMAIN_EN_SECONDNOMBREDECIMAL, on appellerait à nouveau DECIMALISER, en précisant, à ce second appel, que

- SecondNombreRomain "remplace" Romain et

- SecondNombreDecimal "remplace" Decimal.

Romain et Decimal sont ce que nous appellerons des paramètres de la procédure

DECIMALISER. Ils sont encadrés dans le schéma proposé pour insister sur le fait qu'ils font partie

de la procédure spécifiée. A chaque appel de DECIMALISER, ces deux paramètres se verront

nouveau et important, mais il est indispensable d'avoir compris dès à présent à quoi ces paramètres sont utiles.

Il est inutile, pour l'instant, de se préoccuper des détails syntaxiques. Ainsi, le fait que le paramètre Decimal est précédé de la mention var ne sera expliqué que plus loin (voir page 159). De la même manière, les trois dernières actions complexes peuvent se résumer en une seule :

ROMANISER(Decimal : entier long; var Romain : NombreRomain)

Decimal

de type entier long

Transformer Decimal en son équivalent en chiffres

romains Romain Romain

de type NombreRomain avec

Avant l'exécution de ROMANISER Après l'exécution de ROMANISER - Decimal paramètre de type entier long qui contient un nombre

entier entre 0 et 998001.

- Romain, paramètre de type NombreRomain, contenant le nombre en chiffres romains correspondant à Decimal.

Il faut noter que ces deux paramètres Decimal et Romain accompagnant ROMANISER n'ont rien à voir (même s'ils portent des noms identiques) avec les deux paramètres Romain et

Decimal accompagnant DECIMALISER.

Et au moment des appels, on appellerait à trois reprises la même procédure ROMANISER, mais on préciserait :

- pour la transformation de la somme : - Decimal est SommeDecimal et

- Romain est à comprendre comme SommeRomain;

- en ce qui concerne la différence :

- Decimal est la valeur absolue de DifferenceDecimal;

- Romain est à comprendre comme DifferenceRomain;

Il faut bien noter que ROMANISER ayant comme tâche de transformer le nombre décimal qu'on lui passe (à travers le paramètre Decimal), il faudra, lors de l'appel destiné à "romaniser" la différence contenue dans DifferenceDecimal, remplacer le paramètre Decimal non par

DifferenceDecimal mais par la valeur absolue de cette dernière.

- en ce qui concerne le produit : - Decimal est ProduitDecimal et

- Romain est en réalité ProduitRomain.

Avec cette réécriture qui fait seulement apparaître deux procédures ROMANISER et DECIMALISER, assorties de paramètres, là où 5 procédures avaient primitivement été isolées, la marche à suivre principale devient :

AVERTIR Répéter

Lis PremierNombreRomain PremierNombreRomain,

Lis SecondNombreRomain SecondNombreRomain de type NombreRomain

DECIMALISER(PremierNombreRomain, PremierNombreDecimal)

PremierNombreDecimal de type entier long

DECIMALISER(SecondNombreRomain, SecondNombreDecimal)

SecondNombreDecimal de type entier long SommeDecimal PremierNombreDecimal + SecondNombreDecimal SommeDecimal de type entier long DifferenceDecimal PremierNombreDecimal -SecondNombreDecimal DifferenceDecimal entier long

ProduitDecimal PremierNombreDecimal * SecondNombreDecimal ProduitDecimal entier long

ROMANISER(SommeDecimal, SommeRomain)

SommeRomain de type NombreRomain

ROMANISER(abs(DifferenceDecimal), DifferenceRomain)

DifferenceRomain de type NombreRomain

ROMANISER(ProduitDecimal, ProduitRomain)

ProduitRomain de type NombreRomain

Affiche SommeRomain

Si DifferenceDecimal = 0 alors Affiche "Différence nulle" sinon

Si DifferenceDecimal > 0 alors Affiche DifferenceRomain

sinon

Affiche "-" suivi de DifferenceRomain Affiche ProduitRomain

Demander à l'utilisateur s'il souhaite recommencer et lire Reponse

jusqu'à ce que Reponse= 'N' Reponse de type caractère

On notera dès à présent que lors de l'appel des procédures assorties de paramètres, chacun des paramètres définis dans les spécifications (= la description du "Quoi faire ?") de ces procédures se voit associer une information ou une variable du programme principal. Il faut donc mettre en parallèle la définition de la procédure et de ses paramètres et son appel, qui précise les valeurs prises, lors de cet appel, par les paramètres. Ainsi, par exemple :

Définition : DECIMALISER( Romain Decimal )

1er appel :DECIMALISER(PremierNombreRomain,PremierNombreDecimal) Définition : DECIMALISER( Romain Decimal )

2ème appel : DECIMALISER(SecondNombreRomain,SecondNombreDecimal)