Utilisation de Switch a la place de if else if else (Arduino

Résolu
Drum22 -  
 Drum22 -
Bonjour,

Les exemples que je trouve pour
switch
sont souvent comparés à des tests d'égalités (
== 1
,
== 2
etc.)
  • Comment utiliser des
    >=
    ou
    <=
    , pour définir des plages de valeurs, comme dans une gamme de notes de musique (par exemple, la note "Si" correspond à la plage allant de
    495
    à
    527
    ) ?
  • Comment transformer le code ci-dessous avec un
    switch
    ?


if (sensorValue >= 528) {
    // note = Do4         Frequence = 528;
    note = "Do 4";
} else if (sensorValue >= 495) {
    // note = Si            Frequence = 495;
    note = "Si";
} // etc...


Merci de votre aide
a++

6 réponses

  1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     
    Bonjour,

    C'est simple, tu ne peux pas, à moins d'énumérer toutes les valeurs de ta plage :-) De plus un switch nécessite que la valeur testée soit un type entier (e.g.
    char
    ,
    int
    ,
    uint
    , ...), donc si ton code doit marcher avec un
    float
    ou un
    double
    , tu ne peux pas t'en sortir avec un
    switch
    .

    En fait c'est assez normal, c'est inhérent à la manière dont
    switch
    fonctionne : c'est relativement proche de la notion de labels et de
    goto
    .

    Note enfin que dans la version
    if ... else if ...
    il faut être vigilant à l'ordre dans lequel tu fais tes tests si tu ne contrôle que l'une des deux bornes de chaque plage de valeurs.

    Après, une manière plus élégante d'écrire ton code qui associe à chaque intervalle la donnée qui nous intéresse un arbre d'intervalles, mais comme ici les intervalles sont disjoints, on peut directement utiliser un arbre binaire de recherche. Comme aucune de ces structure n'est implémentée directement en C, et vu qu'il y a peu de notes, tu peux te contenter d'une structure moins efficace mais plus simple à coder, par exemple un bon vieux tableau.

    Ton code pourrait du coup ressembler à ceci :

    #include <stdio.h>
    
    typedef struct _note_t {
        unsigned short min;
        unsigned short max;
        const char * name;
    } note_t;
    
    static const note_t NOTES[] = {
        {495, 528, "Do4"},
        {470, 495, "Si3"},
        // ...
    };
    
    const char * find_note(double freq) {
        const note_t * note = &(NOTES[0]);
        unsigned num_notes = sizeof(notes) / sizeof(note_t);
        for (unsigned i = 0; i < num_notes; i++, note++) {
            if (note->min <= freq && freq < note->max) {
                return note->name;
            }   
        }                                     
        return NULL;                          
    }                                         
    
    int main(){
        double freqs[] = {400, 470, 475, 495, 500, 530};
        unsigned num_freqs = sizeof(freqs) / sizeof(double);
        const double * pfreq = &freqs[0];
        for (unsigned i = 0; i < num_freqs; i++, pfreq++) {
            double freq = *pfreq;
            printf("find_note(%lf) = %s\n", freq, find_note(freq));
        }   
        return 0;               
    }


    ... ce qui donne :

    (mando@silk) (~) $ gcc notes.c && ./a.out 
    find_note(400.000000) = (null)
    find_note(470.000000) = Si3
    find_note(475.000000) = Si3
    find_note(495.000000) = Do4
    find_note(500.000000) = Do4
    find_note(530.000000) = (null)


    Bonne chance
    1
    1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       
      La structure en tableau est-elle réellement moins efficace?
      N'est-ce pas plutôt la méthode choisie pour parcourir le tableau qui est peu efficace?
      0
      1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944 > yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention  
         
        Effectivement, sous réserve que le tableau soit trié selon les fréquences des notes, tu peux faire une dichotomie et ainsi trouver la note en O(log(n)). Tu aboutis alors à la même complexité que pour comme pour un arbre binaire. Cependant, si cette hypothèse n'est pas vérifiée (par exemple parce que les notes ne sont pas données selon l'ordre prévu par la dichotomie), alors il faut faire la recherche en O(n) en parcourant chaque élément du tableau comme je l'ai fait.
        0
  2. georges97 Messages postés 14606 Date d'inscription   Statut Contributeur Dernière intervention   2 932
     
    Bonjour,

    Sauf erreur de ma part, l'exemple suivant permet de tester une condition correspondant à un intervalle et de la traiter dans un switch:

    https://stackoverflow.com/questions/45645087/if-else-and-string-in-a-switch-case

    voir également:

    https://www.locoduino.org/spip.php?article23

    Ce serait bien de revenir nous dire si cela convient ou si je me suis complètement fourvoyé concernant votre demande.
    1
    1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 944
       
      Bonjour georges,

      Non, dans les deux exemples que tu donnes,
      switch
      ne fait pas un test permettant de vérifier si la valeur appartient ou non à un intervalle, mais s'il coïncide avec certaines valeurs discrètes.

      En particulier, cela signifie que si l'on passe une une valeur comprises entre deux de ces valeurs discrètes, le
      switch
      t'enverra dans le bloc
      default:
      .
      0
      1. georges97 Messages postés 14606 Date d'inscription   Statut Contributeur Dernière intervention   2 932 > mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention  
         
        Bonjour mamiemando,

        Merci pour l'explication. Je continue mon apprentissage.

        A bientôt
        0
  3. Drum22
     
    Oui ! D'après cette documentation, j'ai bien l'impression qu'il s agisse toujours de tests de "pure" égalite !! (ou de progression de 1 en 1 ! on n'est pas rendu ...)
    donc, l ordre switch ne répond sans doute pas à ma problématique ?
    Je cherchais l'équivalent comme dans d autres langages, il y avait
    CASEQ
    ,
    CASLT
    ,
    CASGT
    par exemple...
    Sinon, je ne suis pas abonné au
    switch
    , si une autre instruction fait le job, je suis preneur. ;-)
    Merci de vos retours
    a++
    0
  4. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  5. Drum22
     
    Merci à tous pour vos réponses. Je pensais "simplifier" la structure de mes tests (fort heureusement indentés !), mais le code propose reste assez "complexe" pour quelqu'un comme moi qui aborde tout juste le C++ pour Arduino. Je "lis" via une cellule photosensible pour "'retranscrire" sur un buzzer. Je vais donc conserver mon ancien code mais vous remercie encore pour vos idées de code.

    Prenez soin de vous
    0
    1. Utilisateur anonyme
       
      Juste une petite remarque, tu as posté ta question dans le forum C, donc on a tous répondu en fonction.
      C++ pour ce cas précis c’est pareil, mais pas toujours.
      Je déplace dans le bon forum
      0
  6. Drum22
     
    Pardon en cliquant sur la rubrique, j ai vu "C" ... je me suis dit que ca allait pile poil ! Un grand merci à tous les intervenants, en tous cas, ça m'a bien aidé ! J ai "quand même" poussé, non pas la chansonnette, mais le code pour les tableaux.
    Ça simplifie vachement le code (et le nombre de lignes !!) ;-)

    Encore merci

        // Recherche dans le tableau [0,7] (frequence & nom de la note)
        for (int i = 0 ; i < Tab_Max; ++i)
         {
            // Si la recherche n a pas abouti, on compare
            if ((sensorValue >= Tab_Notes[i]) && (Trouve == 0))  
             {
                Frequence = Tab_Notes[i];
                Note      = Lib_Notes[i];
                Trouve    = 1;
             }
         }
        
        // Si Trouve = 0... (pas abouti)
        // la frequence est plus basse que Do3 ( <264 ), 
        // forcer a Do3 inferieur
        if (Trouve == 0)
        {
            Frequence = Tab_Notes[Tab_Max] - 64;    // frequence = 200
            Note      = "en dessous";
        }
    0