Forum: Mikrocontroller und Digitale Elektronik Verschachtelte IFs ohne Redundanz möglich?


von Christian M. (Gast)


Lesenswert?

Eigentlich ein allgemeines Programmierproblem. Habe gerade folgenden 
Code:
1
If analog_richtung Then
2
  If analog_pwm Then
3
    Low IN1
4
  Else
5
    High IN1
6
  Endif
7
Else
8
  If analog_pwm Then
9
    Low IN2
10
  Else
11
    High IN2
12
  Endif
13
Endif

Wie man sieht, unterscheiden sich die beiden Zweige minimal. Kann man 
das verschönern und die Redundanz rausnehmen? Da es sich hier um 
konkreten Mikrocontroller-Code (Oshonsoft Basic für PIC16) handelt wäre 
noch die Frage, was für eine Variante kleiner, schneller oder schöner 
ist.

Hier soll er schnell sein, weil in der INT.

Dieses Beispiel ist jetzt einfach, vielleicht zu einfach um es zu 
vereinfachen, zeigt aber die Problematik auf. Ich hatte schon 
(Windows-)Programme geschrieben, die hatten riesen Redundanz im Code 
wegen paar Kleinigkeiten.

Man kann das Problem sogar noch erweitern auf z.B. Datenblätter. Die 
habe ich einmal in einem Ordner mit allen DBs, aber auch im Ordner eines 
Projekts. OK, beim heutigen Speicherplatz kein Problem, ist aber nicht 
schön. Und Photos, wo mache ich die rein? In den Projektordner oder zu 
den Photos? Sind Hardlinks die Lösung?

Gruss Chregu

von A. S. (Gast)


Lesenswert?

Switch Case, wenn Du die 2 unabhängigen binären zustande zu einem 
zusammenfassen kannst.

Ansonsten je nach Komplexität der Körper auch Funktionen, Datenarrays 
etc.

von ... (Gast)


Lesenswert?

Die ist doch nur code-redundanz, aber in jedem Ausführungspfad sind 
genau nur so viele IFs wie nötig. Egal, wie irgendein IF ausgeht, es 
sind zum Schluss nur 2 Sprünge die gemacht werden. Die Schönheit des 
Codes hat hier nichts mit der Geschwindigkeit zu tun.

von Zoidberg (Gast)


Lesenswert?

If analog_richtung Then
 pin = IN1
Else
 pin = IN2
Endif


If analog_pwm
 Low pin
Else
 High pin
Endif


Finde ich gut lesbar. Ich persönlich würde pin wahrscheinlich immer 
vorhalten und nur umschalten wenn von ein Richtungswechsel passiert.

von Peter D. (peda)


Lesenswert?

Eleganter ist es, beide Bedingungen EXOR zu verknüpfen. Das erspart dann 
das 2-malige Hinschreiben und Lesen.
Schneller ist es aber nicht.

von Klaus R. (klara)


Lesenswert?

Zoidberg schrieb:
> Finde ich gut lesbar.

Man sollte den Source immer möglichst gut lesbar gestalten, so daß man 
ihn auch noch nach zwei oder drei Jahren wieder schnell und sicher 
versteht.
mfg Klaus

von A. S. (Gast)


Lesenswert?

Peter D. schrieb:
> Eleganter ist es, beide Bedingungen EXOR zu verknüpfen. Das erspart dann
> das 2-malige Hinschreiben und Lesen.
> Schneller ist es aber nicht.

Der TO hat ja genau keine Redundanz: Er hat 2 "Pins" (IN1, IN2) und je 2 
Zustände. Also genau 4 Aktionen, getriggert durch 2*2 Eingangszustände.

von Christian M. (Gast)


Lesenswert?

A. S. schrieb:
> Der TO hat ja genau keine Redundanz

Ja hast schon Recht. Sehen wir es so an: In der zweiten Ebene sind beide 
Male die genau gleichen Abfragen, sie wären austauschbar mit den 
Aeusseren. Es ist zweidimensional! Eine Tabelle.
1
+---------+--------------+--------------+
2
¦         ¦ richtung = 1 ¦ richtung = 0 ¦
3
+---------+--------------+--------------+
4
¦ pwm = 1 ¦ Low IN1      ¦ High IN1     ¦
5
+---------+--------------+--------------+
6
¦ pwm = 0 ¦ Low IN2      ¦ High IN2     ¦
7
+---------+--------------+--------------+

Man könnte auch die Y-Achse als äussere Abfrage nehmen. Die Tabelle kann 
viel grösser sein, oder sogar mehr als zwei Dimensionen haben. Ich meine 
nur dass sich die inneren Abfragen immer wiederholen!

Gruss Chregu

von Peter D. (peda)


Lesenswert?

A. S. schrieb:
> Der TO hat ja genau keine Redundanz:

Stimmt, es sind 4 Fälle.
Damit man nicht eine Bedingung mehrfach hinschreiben muß, kann man beide 
in eine Variable kombinieren und per switch/case auswerten.
In C würde das so aussehen:
1
  uint8_t i = !!analog_richtung;
2
  if (analog_pwm)
3
    i |= 2;
4
  switch (i){
5
    case 0: High_IN2(); break;
6
    case 1: High_IN1(); break;
7
    case 2: Low_IN2(); break;
8
    case 3: Low_IN1(); break;
9
  }

von MaWin (Gast)


Lesenswert?

Peter D. schrieb:
> In C würde das so aussehen:

Echt super als Anfang für den Obfuscated C Contest.

von Zoidberg (Gast)


Lesenswert?

Die Eingangsgrößen als bits in einem Decoder-Wort zu sehen ist doch gar 
nicht so schlecht als Idee.
Lesbarer finde ich (zumindest bei den zwei Werten) aber immer noch 
meinen obigen Vorschlag.

1
uint8_t decode = analog_richtung + 2*analog_pwm; //ggf. + 4* analog_gimmick; 
2
3
  switch (i){
4
    case 0: High_IN2(); break;
5
    case 1: High_IN1(); break;
6
    case 2: Low_IN2(); break;
7
    case 3: Low_IN1(); break;
8
    //(...)
9
  }

Muss nur sichergestellt werden, dass decode korrekt zusammengebaut wird, 
also der Wertebereich der Eingangsgrößen immer 0/1 ist. (Oder halt 
anders schieben)
Und man kann die Logiktabelle noch in den Code kommentieren.

von Christian M. (Gast)


Lesenswert?

Zoidberg schrieb:
> switch (i){

Du meinst
1
switch (decode){

Oder ich fände noch praktisch:
1
uint8_t decode = analog_richtung + %00000010*analog_pwm; //ggf. + %00000100* analog_gimmick; 
2
3
  switch (decode){
4
    case %00000000: High_IN2(); break;
5
    case %00000001: High_IN1(); break;
6
    case %00000010: Low_IN2(); break;
7
    case %00000011: Low_IN1(); break;
8
    //(...)
9
  }

Gruss Chregu

von Sven K. (quotschmacher)


Lesenswert?

Zoidberg schrieb:
> also der Wertebereich der Eingangsgrößen immer 0/1 ist

dafür ist ja die doppelte negierung da

Peter D. schrieb:
> uint8_t i = !!analog_richtung;

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

Zoidberg schrieb:
> uint8_t decode = analog_richtung + 2*analog_pwm; //ggf. + 4*
> analog_gimmick;
>
>   switch (i){
>     case 0: High_IN2(); break;
>     case 1: High_IN1(); break;
>     case 2: Low_IN2(); break;
>     case 3: Low_IN1(); break;
>     //(...)
>   }

Dann vielleicht sogar
1
#define DIR_HI  0x00
2
#define DIR_LO  0x02
3
#define PWM_2   0x00
4
#define PWM_1   0x01
5
6
switch(analog_richtung | (analog_pwm << 1)) {
7
  case DIR_HI | PWM_2: High_IN2(); break;
8
  case DIR_HI | PWM_1: High_IN1(); break;
9
  case DIR_LO | PWM_2: Low_IN2(); break;
10
  case DIR_LO | PWM_1: Low_IN1(); break;
11
}

EDITH sagt: aber am besten mag ich immer noch den Origonal-Code vom TO!

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Christian M. schrieb:
> Wie man sieht, unterscheiden sich die beiden Zweige minimal. Kann man
> das verschönern und die Redundanz rausnehmen?

Immer wenn man strukturell identischen Code hat (Redundanz), ist das ein 
Indiz, dass man diese Redundanz durch generischen Code herausnehmen 
kann.

In einer Sprache, die das generische Paradigma unterstützt, wie etwa 
C++, könnte man folgendes formulieren:
1
#include <iostream>
2
#include <type_traits>
3
4
// das folgende wäre im echten Leben eine Pin-Klasse, die eh schon da ist.
5
template<bool B> using ActiveHigh = std::integral_constant<bool, B>;
6
7
template<typename ActiveHigh> 
8
struct In {
9
    inline static void activate(bool b) {
10
        if (b ^ ActiveHigh::value) {
11
            // whatever todo for high()            
12
        }    
13
        else {
14
            // whatever todo for low()
15
        }
16
    }
17
};
18
19
// der tatsächlich benötigte Code
20
21
using In1 = In<ActiveHigh<true>>;
22
using In2 = In<ActiveHigh<false>>;
23
24
int main() {
25
    bool analogRichtung{};
26
    bool analogPwm{};
27
 
28
    if (analogRichtung) {
29
        In1::activate(analogPwm);
30
    }
31
    else {
32
        In2::activate(analogPwm);
33
    }
34
}

von Sven K. (quotschmacher)


Lesenswert?

Wilhelm M. schrieb:
> könnte man folgendes formulieren:

wenn man das zusammenfasst sind es aber noch immer die zwei 
if-statements vom anfang. nur anders geschrieben.

von Wilhelm M. (wimalopaan)


Lesenswert?

Sven K. schrieb:
> wenn man das zusammenfasst sind es aber noch immer die zwei
> if-statements vom anfang. nur anders geschrieben.

Tja, 4 Alternativen.

von Zoidberg (Gast)


Lesenswert?

>dafür ist ja die doppelte negierung da


Ja, schon klar, allerdings hat der Poster einen Basic Dialekt und MaWin 
regte eine offensichtlichere Schreibweise an.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.