switch-case vs. if-else?



  • Gast3 schrieb:

    und es ist doch eigentlich normal Zustandskomplexität mit If-Statements auf einfache Zustände zu mappen und diesen dann mit switch-case weiter zu verarbeiten - daher verstehe ich diese If-oder-Switch-Frage und die Diskussionen hier nicht wirklich

    Dann lies' mal das Ursprungsposting. Es geht um Rechenzeiteinsparung.

    Fakt ist, dass ein Ablauf

    if (bedingung)
    {
    }
    else if (bedingung)
    {
    }
    else if (bedingung)
    {
    }
    else if (bedingung)
    {
    }
    

    um so mehr Zeit benötigt, um so weiter unten die erfüllte Bedingung steht - schlicht weil de CPU jede Bedingung einzeln überprüfen muss.

    Deswegen wurde ja switch-case eingeführt, welches sofort auf den passenden Wert springt. "bedingung" muss hier logischerweise ein Vergleich auf Gleichheit sein, sonst lässt sich switch-case nicht verwenden.

    Das Problem: switch-case hat per se erst mal ein wenig Overhead, weil es mit irgend welchen lustigen Jumptables arbeitet.

    Die eigentliche Frage war hier, ab wie vielen if-else-Kaskadierungen sich ein Ersetzen durch switch-case lohnt, weil dann diese Jumptables effektiver sind, als für einen Durchlauf bis zur letzten Bedingung.

    Nur scheint das eine Frage zu sein, die in diesem Forum noch nicht mal verstanden wird, geschweige denn zu der eine brauchbare Antwort möglich ist.

    Statt dessen glänzt hier ein "Supermoderator" mit geradezu peinlichen Aussagen, vo denen man ernsthaft warnen sollte.



  • @SeppJ

    Wenn die Logik dynamisch ist (oder sehr komplex, was bedeutet, dass man ernsthaft in Betracht ziehen sollte, sie dynamisch zu machen), dann würde das ganze halt durch Lookups in passende Datenstrukturen erfolgen, anstatt durch fest-codierte Anweisungen in der Programmlogik. Macht effektiv das gleiche (ein Arrayzugriff und ein Jumptable tun sich nicht viel), hält aber den Code einfacher und flexibler.

    wieso veränderst du den Kontext der Ursprungsfrage?
    es ging hier nirgends um komplexe dynamische Fallunterscheidungen - die man wo ich dir recht geben lieber anders lösen sollte - aber das war hier einfach nicht die Frage - und wenn du hohe Verarbeitungsraten fährst ist "(ein Arrayzugriff und ein Jumptable tun sich nicht viel)" ziemlich weit aus dem Fenster gelehnt - wir kennen doch gar nicht den Kontext - 1ms Echtzeit, 10 Mio Datenpakete in 10ms, und und und - klar ist es nur wenn man genau dein Beispiel von einem einfachen dynamischen Terminplaner nimmt - mit den Features die nur du kennst und dann damit argumentiert



  • So, damit sich hier nicht noch mehr Unwissenheit, Halbwahrheiten und Gerüchte verbreiten, lasse ich mal an meinen Erkennissen aus anderen Foren teilhaben: die alte switch-case-Geschwindigkeitsregel ist hinfällig.

    Tatsächlich schauen sich (gute) moderne Compiler die verwendeten Werte an und machen aus einem switch-case - wenn sinnvoll - schon mal das Äquivalent einer if-else-Kette. Oder eine Jumptable. Oder einen binären Abfragebaum. Oder was an der Stelle sonst sinvoll ist.

    Die daraus abzuleitende Regel wäre eher, switch-case immer dann zu verwenden, wenn es übersichtlicher wird, also IMHO so ab drei Abfragen.


  • Mod

    Gast3 schrieb:

    wieso veränderst du den Kontext der Ursprungsfrage?

    Was ist denn die Ursprungsfrage? Ob man switch in der Praxis oft (oder überhaupt) braucht? Das war jedenfalls die Frage, die ich dir beantworten wollte. Dass ich bewusst nicht auf Tomots Unsinn eingehe, habe ich bereits klar gemacht.


  • Mod

    Tomot schrieb:

    Tatsächlich schauen sich (gute) moderne Compiler die verwendeten Werte an und machen aus einem switch-case - wenn sinnvoll - schon mal das Äquivalent einer if-else-Kette. Oder eine Jumptable. Oder einen binären Abfragebaum. Oder was an der Stelle sonst sinvoll ist.

    Erste Antwort hier in diesem ach so inkompetenten Forum:

    afdasfd schrieb:

    oO

    Erinnerungen mögen trügen. Im Grunde sollte es egal sein. Der Compiler dürfte das zum gleichen Code verhackstücken.

    Du kannst ja mal zum Test dem Compiler deiner Wahl sagen, dass er den Assembler Code ausspucken soll. Dort kannst du dann schön vergleichen.



  • SeppJ schrieb:

    Erste Antwort hier in diesem ach so inkompetenten Forum:

    Dir muss man echt lesen helfen, oder? Diese Antwort beschreibt, dass ein if-else auch mal in ein switch-case-Äquivalent umgewandelt wird.

    Davon habe ich aber NICHTS geschrieben! Es scheint nur das Gegenteil der Fall zu sein, dass ein switch-case auch mal zu einem if-else-Äquivalent (oder eben zu ganz was anderem) umgewandelt wird.

    Und dass if-else nicht zwangsläufig zum gleichen Code wie switch-case wird, kann man unter gcc.godbolt.org ganz leicht überprüfen.



  • Unregistrierte sind mir sowieso suspekt.
    SeppJ ist ein hochanständiger und wissender Mensch, ihr kleinen Schei**haufen da außen.



  • SeppJ schrieb:

    Praktiker schrieb:

    Für welcher Wochentag ist heute und mach dann etwas entsprechendes ist Switch immer gut zu gebrauchen.
    Wichtig ist nur, dass das, was du ausgeben möchtest, nicht fest im Code ist.

    Zu gebrauchen z.b. für einen Terminplaner.

    Was möchtest du bei einem Terminplaner switchen? Ein Terminplaner ist doch ein Paradebeispiel für eine Anwendung, bei der möglichst viel dynamisch gehalten werden sollte.

    Z.B. welcber Tag ist heute?

    Dinge die du regelmäßig machst, sind sicherlich an einem bestimmten Wochentag, also wird da nach dem Wochentag geswitched.
    Und was an dem Wochentag stattfindet, das entnimmst du dann der Datenstruktur.



  • Lange switch-Statements würde ich fast immer durch eine Lookup-Table ersetzen. Ganz egal welcher micro-optimierte Code hinten rauskommt.

    Wenn ich mir den "Clean Code"-Hut aufsetze, dann muss ich auch SeppJ voll recht geben, aber es mag natürlich Einzelfälle geben in denen ein großes switch oder eine if/else-Tirade tatsächlich Sinn machen könnte...aber man sollte auf jeden Fall mal aufmerksam werden. Alarmglocken sollten aufleuchten.

    MfG SideWinder



  • Z.B. welcber Tag ist heute?

    calendar.today()? Oder meinst du für die Ausgabe? Dann wohl eher sowas in die Richtung I18N.WeekDays[calender.dayoftheweek()]. switch/if erscheint mir falsch.

    MfG SideWinder



  • [quote="Tomot"]
    Fakt ist, dass ein Ablauf

    if (bedingung)
    {
    }
    else if (bedingung)
    {
    }
    else if (bedingung)
    {
    }
    else if (bedingung)
    {
    }
    

    um so mehr Zeit benötigt, um so weiter unten die erfüllte Bedingung steht - schlicht weil de CPU jede Bedingung einzeln überprüfen muss.
    [QUOTE]

    So würde man nicht programmieren.

    Wenn man schon if nimmt, dann würde man hier die Bedingungen in Gruppen zusammenfassen und nach diesen verschachteln und erst in der eingebetten if Bedingung genauer abfragen.

    Einfaches Beispiel.
    Buchstaben A-Z, welcher wurde eingegeben?

    if (eingabe <= 'M'){
      if (eingabe <= 'F'){
         /* und nun einzeln detailiert, wobei es sich hier danns schon lohnt switch zu nehmen, aber im Grunde würde wäre es wohl am schnellsten, wenn man für A-Z ein switch verwendet, mir ging es jetzt aber nur um mal kurz etwas zu veranschaulichen und ein besseres Beispiel ist mir nicht eingefallen */
      } else {
         // behandelt G-M
      }
    else {
      if (eingabe <= 'S'{
        // ... wie siehe oben, behandelt N-S
      } else {
        // behandelt T-Z
      }
    
    }
    

    Das Problem: switch-case hat per se erst mal ein wenig Overhead, weil es mit irgend welchen lustigen Jumptables arbeitet.

    Die eigentliche Frage war hier, ab wie vielen if-else-Kaskadierungen sich ein Ersetzen durch switch-case lohnt, weil dann diese Jumptables effektiver sind, als für einen Durchlauf bis zur letzten Bedingung.

    Ich würde sagen, das hängt von Fall zu Fall und von Compiler zu Compiler ab.
    Du wirst es testen und vergleichen müssen.
    Dazu Vergleiche von Strings sind sicherlich aufwendiger als reine Zahlenwerte.
    Man muss sich also in die Assemblersicht versetzten und überlegen, wie man das optimieren könnte, also wie es der Compiler optimieren würde.



  • SideWinder schrieb:

    Z.B. welcber Tag ist heute?

    calendar.today()? Oder meinst du für die Ausgabe? Dann wohl eher sowas in die Richtung I18N.WeekDays[calender.dayoftheweek()]. switch/if erscheint mir falsch.

    MfG SideWinder

    Und das hast du alles in einem µC?
    Also ne fette lib?



  • Ich weiß nicht ob ich einem µC unbedingt Wochentage internationalisiert am Schirm anzeigen muss. Trotzdem sind die meisten µC heute schon stark genug um es nicht mehr notwendig zu haben jeden Cycle zweimal umzudrehen und deswegen ein Dictionary-Lookup lieber zu einem switch auszuflachen. Mag sein, dass solche State Machines via switch in manchen real time-Systemen von Belang sind, aber davon war ja hier überhaupt keine Rede. Wenn der OP eine so allgemeine Frage stellt sollte er sich auf eine Antwort für den 99,999% case einstellen.

    MfG SideWinder



  • Das kann man so auch nicht unbedingt einschätzen. Prefetching, Caching usw. könnte auch viel ausmachen. Ich habe schon Jump Tables mit Funktionszeigern hinbekommen, die schneller als switch-case waren.



  • Hi,

    was spricht daegen, beides zu kombinieren?
    Ich hab für ein Syntaxhighlighting zuerst den Switch nach dem Anfangsbuchstaben genommen, und dann mit den konkreten Werten über ifs unterschieden.
    Alternativ kann es sich auch lohnen, wie man eine Schlange von 50 ifs binär zerlegt, so nach ner Art binärem Suchalgoritmus? Dann hat man zwar nie den kürzesten Fall, aber immer einen überschaubaren.
    Außerdem ist die Zahl der Fälle, wo es wirklich auf die letzte Milisekunde oder das letzte Byte ankommt recht gering.
    Viel wichtiger ist ein übersichtlicher Quelltext den man auch nach 5 Jahren noch begreift.
    Auch sehe ich

    void switch_test(int a)
    {
      switch(a)
      {
        case 1: x = 1; y = 2; z = 3; break;
        case 2: x = 2; y = 1; z = 3; break;
        case 3: x = 3; y = 2; z = 1; break;
      }
      return 0;
    }
    

    als um Welten übersichtlicher an als

    void switch_test(int a)
    {
      switch(a)
      {
        case 1:
          x = 1;
          y = 2;
          z = 3;
          break;
        case 2:
          x = 2;
          y = 1;
          z = 3;
          break;
        case 3:
          x = 3;
          y = 2;
          z = 1;
          break;
      }
      return 0;
    }
    

    Auch wenn sich dabei vielen die Fußnägel hochrollen.

    Gruß Mümmel


Anmelden zum Antworten