Verschachtelte IFs ohne Redundanz möglich?

Gast #6045659
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
Gast #6045665
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.
Gast #6045668
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.
Gast #6046329
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.
Gast #6046577
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
#6046582
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
  }
Gast #6046640
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.
Gast #6046693
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
#6046781
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!
#6046929
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren