Aller au menu - Aller au contenu

Icône TP : Calculs en ligne de commande

Mise à jour : 02/02/2012
Difficulté : Facile Facile Creative Commons BY-NC-SA
22 955 visites depuis 7 jours, dont 154 sur ce chapitre classé 15/786
Et voici un nouveau TP qui va nous permettre de récapituler un peu tout ce que nous avons vu.
Au programme, des if, des switch, des méthodes, des boucles et... de la ligne de commande bien sûr !

Grâce à nos connaissances grandissantes, nous arrivons à augmenter la difficulté de nos exercices et c'est une bonne chose. Vous verrez que dans le moindre petit programme, vous aurez besoin de toutes les notions que nous avons apprises.

Allez, ne traînons pas trop et à vous de jouer travailler.
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Instructions pour réaliser le TP

L’objectif de ce TP est de réaliser un petit programme qui permet d’effectuer une opération mathématique à partir de la ligne de commande.

Il va donc falloir écrire un programme que l'on pourra appeler avec des paramètres. En imaginant que le programme s'appelle « MonProgramme », on pourrait l'utiliser ainsi pour faire la somme de deux nombres :

MonProgramme somme 2 5
Ce qui renverra bien sûr 7.

Pour effectuer une multiplication, nous pourrons faire :

MonProgramme multiplication 2 5
et nous obtiendrons 10.

Enfin, pour calculer une moyenne, nous pourrons faire :

MonProgramme moyenne 1 2 3 4 5
ce qui renverra 3.

Les règles sont les suivantes :
  • Il doit y avoir 2 et seulement 2 nombres composant l’addition et la multiplication
  • La moyenne peut contenir autant de nombres que souhaité
  • Si le nombre de paramètres est incorrect, alors le programme affichera un message d’aide explicite
  • Si le nombre attendu n’est pas un double correct, on affichera le message d’aide

Plutôt simple non ?
Alors, à vous de jouer, il n’y a pas de subtilité.

Correction

STOP.

Je relève les copies.

J’ai dit qu’il n’y avait pas de subtilité, mais j’ai un peu menti en fait. J’avoue, c’était pour que vous alliez au bout du développement sans aide. ^^

Pour vérifier que vous avez trouvé la subtilité, essayez votre programme avec les paramètres suivants : MonProgramme addition 5,5 2,5

Obtenez-vous 8 ?


C’était à peu près la seule subtilité, il fallait juste savoir qu’un nombre à virgule s’écrivait avec une virgule plutôt qu’avec un point. Si nous écrivons 2.5, alors le C# ne sait pas faire la conversion.

En vrai, c’est un peu plus compliqué que ça et nous le verrons dans un prochain chapitre, mais l’écriture du nombre à virgule est dépendant de ce qu’on appelle la culture courante que l’on peut modifier dans les paramètres « horloge, langue et région » du panneau de configuration de Windows. Si l’on change le « format de la date, de l’heure ou des nombres » on change la culture courante, et la façon dont les nombres à virgules (et autres) sont gérés est différente.

Nous en reparlerons plus précisément dans un chapitre ultérieur.

Quoiqu'il en soit, voici ma correction du TP :

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
static void Main(string[] args)
{
    if (args.Length == 0)
    {
        AfficherAide();
    }
    else
    {
        string operateur = args[0];
        switch (operateur)
        {
            case "addition":
                Addition(args);
                break;
            case "multiplication":
                Multiplication(args);
                break;
            case "moyenne":
                Moyenne(args);
                break;
            default:
                AfficherAide();
                break;
        }
    }
}

static void AfficherAide()
{
    Console.WriteLine("Utilisez l'application de la manière suivante :");
    Console.WriteLine("MonProgamme addition 2 5");
    Console.WriteLine("MonProgamme multiplication 2 5");
    Console.WriteLine("MonProgamme moyenne 2 5 10 11");
}

static void Addition(string[] args)
{
    if (args.Length != 3)
    {
        AfficherAide();
    }
    else
    {
        double somme = 0;
        for (int i = 1; i < args.Length; i++)
        {
            double valeur;
            if (!double.TryParse(args[i], out valeur))
            {
                AfficherAide();
                return;
            }
            somme += valeur;
        }
        Console.WriteLine("Résultat de l'addition : " + somme);
    }
}

static void Multiplication(string[] args)
{
    if (args.Length != 3)
    {
        AfficherAide();
    }
    else
    {
        double resultat = 1;
        for (int i = 1; i < args.Length; i++)
        {
            double valeur;
            if (!double.TryParse(args[i], out valeur))
            {
                AfficherAide();
                return;
            }
            resultat *= valeur;
        }
        Console.WriteLine("Résultat de la multiplication : " + resultat);
    }
}

static void Moyenne(string[] args)
{
    double total = 0;
    for (int i = 1; i < args.Length; i++)
    {
        double valeur;
        if (!double.TryParse(args[i], out valeur))
        {
            AfficherAide();
            return;
        }
        total += valeur;
    }
    total = total / (args.Length - 1);
    Console.WriteLine("Résultat de la moyenne : " + total);
}


Disons que c’est plus long que difficile...

Oui je sais, lors de l’addition et de la multiplication, j’ai parcouru l’ensemble des paramètres alors que j’aurais pu utiliser uniquement args[1] et args[2]. L’avantage c’est que si je supprime la condition sur le nombre de paramètres, alors mon addition pourra fonctionner avec autant de nombres que je le souhaite… Vous aurez remarqué que je commence mon parcours à l’indice 1, d’où la pertinence de l’utilisation de la boucle for plutôt que la boucle foreach.

Notez quand même l’utilisation du mot clé return afin de sortir prématurément de la méthode en cas de problème.

Évidemment, il y a plein de façons de réaliser ce TP, la mienne en est une, il y en a d'autres.

J’espère que vous aurez fait attention au calcul de la moyenne. Nous retirons 1 à la longueur du tableau pour obtenir le nombre de paramètres. Il faut donc faire attention à l’ordre des parenthèses afin que le C# fasse d'abord la soustraction avant la division, alors que sans ça, la division est prioritaire à la soustraction.

Sinon, c'est l'erreur de calcul assurée, indigne de notre superbe application. :-°

Aller plus loin

Ce code est très bien.
Sisi, c'est moi qui l'ai fait :p .

Sauf qu'il y a quand même un petit problème ... d'ordre architectural.

Il a été plutôt simple à écrire en suivant l'énoncé du TP mais on peut faire encore mieux. On peut le rendre plus facilement maintenable en le ré-architecturant différemment.

Observez le code suivant :

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
static void Main(string[] args)
{
    bool ok = false;
    if (args.Length > 0)
    {
        string operateur = args[0];
        switch (operateur)
        {
            case "addition":
                ok = Addition(args);
                break;
            case "multiplication":
                ok = Multiplication(args);
                break;
            case "moyenne":
                ok = Moyenne(args);
                break;
        }
    }

    if (!ok)
        AfficherAide();
}

static void AfficherAide()
{
    Console.WriteLine("Utilisez l'application de la manière suivante :");
    Console.WriteLine("MonProgamme addition 2 5");
    Console.WriteLine("MonProgamme multiplication 2 5");
    Console.WriteLine("MonProgamme moyenne 2 5 10 11");
}

static bool Addition(string[] args)
{
    if (args.Length != 3)
        return false;

    double somme = 0;
    for (int i = 1; i < args.Length; i++)
    {
        double valeur;
        if (!double.TryParse(args[i], out valeur))
            return false;
        somme += valeur;
    }

    Console.WriteLine("Résultat de l'addition : " + somme);
    return true;
}

static bool Multiplication(string[] args)
{
    if (args.Length != 3)
        return false;
    double resultat = 1;
    for (int i = 1; i < args.Length; i++)
    {
        double valeur;
        if (!double.TryParse(args[i], out valeur))
            return false;
        resultat *= valeur;
    }
    Console.WriteLine("Résultat de la multiplication : " + resultat);
    return true;
}

static bool Moyenne(string[] args)
{
    double total = 0;
    for (int i = 1; i < args.Length; i++)
    {
        double valeur;
        if (!double.TryParse(args[i], out valeur))
            return false;
        total += valeur;
    }
    total = total / (args.Length - 1);
    Console.WriteLine("Résultat de la moyenne : " + total);
    return true;
}


Nous n'affichons l'aide plus qu'à un seul endroit en utilisant le fait que les méthodes renvoient un booléen indiquant si l'opération a été possible ou pas.

D'une manière générale, il est important d'essayer de rendre son code le plus maintenable possible, comme nous l'avons fait ici.
Voilà, j'espère que vous aurez réussi ce TP.

Vous pouvez bien sûr compléter notre calculatrice élémentaire en y rajoutant des notions plus compliquées, comme la racine carrée ou la mise à la puissance. À ce propos, comme les méthodes Math.Sqrt() ou Math.Pow(), il existe de nombreuses méthodes permettant de faire des opérations de toutes sortes. Vous pouvez les consulter à cette adresse dans la documentation en ligne. (oui, je suis d'accord, ce n'est pas tous les jours que nous aurons envie de calculer la tangente hyperbolique d'un angle ... mais sait-on jamais :p ).

En tous cas, n'hésitez pas à faire des variations sur les différents TP que je vous ai proposés, il est toujours intéressant de sortir des sentiers battus.
Chapitre précédent Sommaire Chapitre suivant

Partager

14 commentaires pour "TP : Calculs en ligne de commande"
Note moyenne : 3.05 / 4 (230 votes)
Pseudo Commentaire
Hors ligne king2012 # Posté le 09/03/2012 à 15:42:21

Avis : Très bon

Bonjour, voici ma façon de faire :

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
static void Main(string[] args)
{
    if (args.Length > 0)
    {
        if (((args[0] == "somme" || args[0] == "multiplication")
            && args.Length != 3)
            || (args[0] == "moyenne" && args.Length < 3))
        {
            AfficherAide();
        }
        else
        {
            double nbre = 0;
            for (int i = 1; i < args.Length; i++)
            {
                double valeurArgs = 0;
                if (!double.TryParse(args[i], out valeurArgs))
                {
                    AfficherAide();
                    return;
                }
                else
                {
                    switch (args[0])
                    {
                        case "somme":
                            nbre += valeurArgs;
                            break;
                        case "multiplication":
                            if (i == 1)
                                nbre = valeurArgs;
                            else
                                nbre *= valeurArgs;
                            break;
                        case "moyenne":
                            nbre += valeurArgs;
                            break;
                    }
                }
            }
            foreach (string pValeur in args)
                    Console.Write(pValeur + " ");

            if (args[0] == "somme" || args[0] == "multiplication")
                Console.WriteLine(" = " + nbre);
            else
                Console.WriteLine(" = " + (nbre / (args.Length -1)));
        }
    }
}

static void AfficherAide()
{
    Console.WriteLine("Utilisez l'application de la manière suivante :");
    Console.WriteLine("MonProgamme somme 2 5");
    Console.WriteLine("MonProgamme multiplication 2 5");
    Console.WriteLine("MonProgamme moyenne 2 5 10 11");
}
Hors ligne Darioo2 # Posté le 12/03/2012 à 16:26:43
Avatar

Avis : Bon

Voici le mien:

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
static void Main(string[] args)
        {
            // Si il n'y a pas d'arguments:
            if (args.Length == 0)
            {
                MessageAide();
                Environment.Exit(0);
            }

            // Variables:
            double n1, n2;
            double [] nombres = new double [args.Length-1];
            bool erreur = false;

            // Analyse:
            if(args[0]=="moyenne")
            {
                double total = 0;
                for(int i=1; i<args.Length; i++)
                {
                    if(double.TryParse(args[i], out nombres[i-1]))
                        total += nombres[i-1];
                    else
                        erreur = true;
                }
                if(!erreur)
                    Console.WriteLine("La moyènne est de: "+total/nombres.Length);
            }
            else if(args[0]=="addition")
            {
                if(double.TryParse(args[1], out n1) && double.TryParse(args[2], out n2))
                    Console.WriteLine("Le résultat de l'addition est de: "+(n1+n2));
            }
            else if (args[0] == "multiplication")
            {
                if (double.TryParse(args[1], out n1) && double.TryParse(args[2], out n2))
                    Console.WriteLine("Le résultat de la multiplication est de: " + (n1 * n2));
            }
            else
            {
                Console.WriteLine("Erreur lors de la saisie !\n");
                MessageAide();
            }
            
            // En cas d'erreur de paramètres:
            if (erreur)
            {
                Console.WriteLine("Erreur avec les paramètres saisis !\n");
                MessageAide();
            }
        }

        static void MessageAide()
        {
            Console.WriteLine("Veuillez entrer:");
            Console.WriteLine("\t \"addition\" suivi de 2 nombres a additioner");
            Console.WriteLine("\t \"multiplication\" suivi de 2 nombres a multiplier");
            Console.WriteLine("\t \"moyenne\" suivi de la quantité de nombres que vous désirez\n");
        }
Hors ligne gfox78 # Posté le 18/04/2012 à 10:07:19
Avatar

Avis : Très bon

Ville : Marcq
Pays : France métropolitaine

Bonjour, encore moi !
En réalisant ce TP relativement facile j'ai été confronté à un curieux problème de portée de variables. Des variables déclarées au début de la méthode 'Main' sont considérées comme locales si elles sont assignées à l'intérieur d'un sous-bloc. Pour l'éviter et permettre la compilation, il faut leur donner un assignation bidon au moment de la déclaration ou un assignation à l'extérieur de tout sous-bloc.
Pour me faire comprendre, je présente mon code, mais son intérêt réside dans les commentaires au début de la méthode 'Main':
Secret (cliquez pour afficher)

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?php
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TpArg
{
    class Program
    {
        static void AfficheAide()
        {
            Console.WriteLine();
            Console.WriteLine(" Ce programme nécessite au moins 3 arguments : ");
            Console.WriteLine("  - le nom de l'opération: addition ou \"+\", soustraction (\"-\"), "); 
            Console.WriteLine("          multiplication (\"*\"), division (\"/\") ou moyenne.");      
            Console.WriteLine("      On peut se contenter des 2 premières lettres; \"ad\", \"so\", \"mu\", \"di\", \"mo\"");
            Console.WriteLine("  - puis 2 opérandes numériques pour les 4 opérations (entiers ou décimaux).");
            Console.WriteLine("  - pour la moyenne, le nombre d'arguments numériques est libre," );
            Console.WriteLine("         mais doit être supérieur à l'unité.");
            Console.WriteLine();
        }
                                    
        static void verifArg(int nbAr, int nbOperands)
        {   // en fait, cela ne sert que si le nombre d'arguments est trop grand ou pour la moyenne
            bool ok = true;
            if (nbOperands > 0)
            {
                if (nbOperands != nbAr - 1) ok = false;
            }
            else
            {
                if (nbAr < 3) ok = false;
            }
            if(!ok) Console.WriteLine("\nErreur dans le nombre d'arguments, on ne prendra que les deux premiers nombres.");
        }
       
        static void Main(string[] args)
        {
            int nbArgs = 0;         
            string signe = "";
            // string signe;   -> message d'erreur si pas assigné : 'Utilisation d'une variable locale non assignée 'signe'  
            string nomOper = "";   // même chose, assignation bidon obligatoire
            string operation;      // pas d'assignement obligatoire car assignée en dehors d'un corps d'une boucle ou d'un switch !
            double operande;
            double resultat;        // ne réclame pas d'assignement ???
            List<double> argList = new List<double>();

            Console.WriteLine("Faire \" help \" ou \" ? \" pour utiliser ce programme avec argument");

 /*         
  *        // ne compile pas si 'operation' n'a pas une assigation bidon  "" au préalable; même type d'erreur que plus haut.
  *         // string operation;    // non assignée, rappel
  *         foreach (string argument in args)
            {
                if (nbArgs == 0)
                {
                    operation = args[0].ToLower();
                }
                else 
                {
                    if (!double.TryParse(argument, out operande))  // je m'assure qu'il s'agit d'arguments numérique
                    {
                        Console.WriteLine("Erreur dans le type d'argument"); return;
                    }
                    else { argList.Add(operande); }
                }
                nbArgs++;
            }   */
           
 ?>

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php          
            // suite du code
            foreach(string argument in args) 
            {
                if ((args[0] == "help") || (args[0] == "?")) { AfficheAide(); return; }
                if(nbArgs > 0)
                {  
                    if(!double.TryParse(argument, out operande))  // je m'assure qu'il s'agit d'arguments numérique
                    {
                        Console.WriteLine("Erreur dans le type d'argument"); return;
                    }
                    else {argList.Add(operande); }
                } 
                nbArgs++;                 
            }
            if (nbArgs < 3) { AfficheAide(); return; }
            operation = args[0].ToLower();   // on met le mot en minuscules
            switch (operation)
            {
                
            /*   case "+":
                    nomOper = "addition";    // on ne peut pas faire cela contrairement au C, ok  */
                case "addition":
                case "+":
                case "ad":
                    nomOper = "addition";  
                    verifArg(nbArgs, 2);
                    signe = " + ";
                    resultat = argList[0] + argList[1];
                    break;
                case "soustraction":
                case "-":
                case "so":
                    nomOper = "soustraction";
                    verifArg(nbArgs, 2);
                    signe = " - ";
                    resultat = argList[0] - argList[1];
                    break;
                case "multiplication":
                case "*":
                case "mu":
                    nomOper = "multiplication";
                    verifArg(nbArgs, 2);
                    signe = " * ";
                    resultat = argList[0] * argList[1];
                    break;
                case "division":
                case "/":
                case "di":
                    nomOper = "division";
                    verifArg(nbArgs, 2);
                    signe = " / ";
                    if (argList[1] == 0) { Console.WriteLine("Division par zéro interdite !!\n"); return; }
                    resultat = argList[0] / argList[1];
                    break;
                case "moyenne":
                case "mo":
                    nomOper = "moyenne";
                    verifArg(nbArgs, -1);
                    resultat = argList.Average();                  
                    break;
                default:
                    Console.WriteLine("\nOpération inconnue"); AfficheAide(); return;
            }
            if (nomOper != "moyenne")
            {
                // Console.WriteLine(operation + " : " + argList[0] + signe + argList[1] + " = " + resultat);
                Console.WriteLine("\n\n"+nomOper + " : " + argList[0] + signe + argList[1] + " = " + resultat+"\n\n");
            }
            else
            {
                Console.WriteLine("\n\nLa moyenne des argments numériques est : " + resultat + " sur "+ argList.Count()+" nombres\n\n");
            }
        }
    }
}
?>


J'ai cru qu'il s'agissait d'une caractéristique du type string qui n'est pas un type simple, mais ce n'est pas le cas. En reprenant le dernier code du chapitre 6 sur les 'blocs et portées' et en mettant la variable 'int age' en début du 'Main', le problème est le même: il faut assigner 'age' avec une donnée 'bidon'.
Secret (cliquez pour afficher)

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
      static void Main(string[] args)
        {
            string prenom = "Nicolas";
            string civilite = "M.";
            //int age;              //Message d'erreur -> "Utilisation d'une variable locale non assignée 'age'".
            int age = 0;            // compile sans problème           
            if (prenom == "Nicolas")
            {
                age = 30;
                Console.WriteLine("Votre age est : " + age);
                switch (civilite)
                {
                    case "M.":
                        Console.WriteLine("Vous êtes un homme de " + age + " ans");
                        break;
                    case "Mme":
                        Console.WriteLine("Vous êtes une femme de " + age + " ans");
                        break;
                }
            }
            if (age >= 18)
            {
                Console.WriteLine(prenom + ", vous êtes majeur");
            }
        } 
?>


Mais alors, en revenant à mon code TP, pourquoi la variable 'double resultat' n'a-t-elle pas besoin d'être assignée lors de sa déclaration alors qu'elle est assignée au sein d'un bloc switch, tout comme la variable 'signe' qui, elle, le nécessite ?
J'avoue ne pas comprendre ?

PS: Evidemment, cette difficulté encourage à suivre le conseil donné dans ce tutoriel de ne déclarer les variables que dans les blocs où elles sont nécessaires, mais dans ce cas, cela imposerait des redondances, comme dans le corrigé du TP.
Hors ligne nico.pyright # Posté le 18/04/2012 à 10:24:19
Groupe : Auteurs

En fait, tu as une erreur de compilation si tu tentes de te servir de ta variable alors qu'elle n'a pas été assignée.
Dans ton cas, tu pourrais potentiellement utiliser la variable signe dans le bloc de code

Code : C#
1
2
3
4
5
if (nomOper != "moyenne")
            {
                // Console.WriteLine(operation + " : " + argList[0] + signe + argList[1] + " = " + resultat);
                Console.WriteLine("\n\n"+nomOper + " : " + argList[0] + signe + argList[1] + " = " + resultat+"\n\n");
            }


car dans le switch, signe n'est pas initialisée dans le bloc default
 
Hors ligne gfox78 # Posté le 18/04/2012 à 13:03:52
Avatar

Avis : Très bon

Ville : Marcq
Pays : France métropolitaine

Le programme que j'ai donné se compile et fonctionne. Mon étonnement est lié simplement, pour des variables déclarées de portée générale dans le 'main', au changement de portée selon l'endroit où je fais l'affectation, à l'intérieur ou l'extérieur des blocs 'foreach' et 'switch' au sein de la méthode 'main'.
La morale est qu'il vaut mieux initier les variables dès leur déclaration.

Voir tous les commentaires