Forum: Compiler & IDEs AVR-GCC/ARM-GCC: Vorzeichen effizient implementieren


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
es ist Sonntag, die Sonne scheint und ich beschäftige mich mit einer 
vielleicht total banalen Frage.

Ich muß ein Vorzeichen änderbar abspeichern und sehr häufig Werte 
inkrementieren. In billig-C-Quelltext sähe das vielleicht so aus:
1
// Einstellungen (nicht const!)
2
// Wie das Vorzeichen gespeichert wird kann ich frei wählen
3
uint8_t config_sign = 0; // 0 oder 1
4
5
int24_t oftgepollteroutine(void) {
6
  static int24_t merker;
7
  if(sign)
8
    merker += getincrement();
9
  else
10
    merker -= getincrement();
11
12
  return merker;  
13
}
oder auch
1
// Einstellungen (nicht const!)
2
// Wie das Vorzeichen gespeichert wird kann ich frei wählen
3
int24_t config_sign = -1; // -1 oder 1
4
5
int24_t oftgepollteroutine(void) {
6
  static int24_t merker;
7
  merker += config_sign*getincrement();
8
9
  return merker;  
10
}
Das Problem wird ja vermutlich sehr häufig auftreten. Aber gibt es da 
für AVR-GCC/ARM-GCC eine Standardlösung?

Viele Grüße
W.T.

von user (Gast)


Lesenswert?

Das erste, beim 2ten muss er multiplizieren, weil config_sign nicht 
konstant ist

von (prx) A. K. (prx)


Lesenswert?

Walter Tarpan schrieb:
> Das Problem wird ja vermutlich sehr häufig auftreten. Aber gibt es da
> für AVR-GCC/ARM-GCC eine Standardlösung?

Prozessor- und Compilerunabhängig gibt es keine Standardlösung, aber 
tendentiell ist bei guten Compilern die if/else Variante schneller, 
zumindest wenn "sign" sich nicht oft oder gut vorhersagbar ändert.

Konkret: Der AVR multipliziert nicht gern. ARMe haben damit idR keine 
Probleme, können hier aber von bedingter Ausführung profitieren (ggf. 
kontrollieren!).

von Walter T. (nicolas)


Lesenswert?

Hihi, ich hätte die zweite Version nicht schreiben sollen. Die ist eher 
für Matlab interessant (Multiplikation ist dort billiger als ein 
branch).

Die Frage ist: Wie macht man diese häufige Problemstellung im 
Embedded-Bereich? Gibt's da vielleicht noch lustige Sachen mit XORs oder 
Zweierkomplement, auf die man nicht beim ersten Gedanken kommt?

: Bearbeitet durch User
von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Hallo Walter,
Walter Tarpan schrieb:
> // Einstellungen (nicht const!)
> // Wie das Vorzeichen gespeichert wird kann ich frei wählen
> uint8_t config_sign = 0; // 0 oder 1
>
> int24_t oftgepollteroutine(void) {
>   static int24_t merker;
>   if(sign)
>     merker += getincrement();
>   else
>     merker -= getincrement();
>
>   return merker;
> }

Was spricht gegen
1
int24_t oftgepollteroutine(void) {
2
   return sing ? getincrement() : -getincrement();
3
}
Oder das Ganze als Makro?

Grüße, Kurt

von (prx) A. K. (prx)


Lesenswert?

PS: Bei den PIC24 ist die zweite Version besser. Einmal mehr: Das ist 
eine Einzelfallfrage.

von (prx) A. K. (prx)


Lesenswert?

Kurt Harders schrieb:
> Was spricht gegen

Ob if/else oder ?: ist eher eine Frage der Ästhetik.

von (prx) A. K. (prx)


Lesenswert?

Walter Tarpan schrieb:
> Gibt's da vielleicht noch lustige Sachen mit XORs oder
> Zweierkomplement, auf die man nicht beim ersten Gedanken kommt?

Im Einerkomplement wirds einfach. ;-)

Wobei das auch beim Zweierkomplement geht, wenn sign = 0/-1 für +/-:
  return (getincrement() ^ sign) - sign;
aber auch hier hängt es vom Einzelfall ab, ob das was bringt.
Astrein sauberes C ist das zudem nicht.

von Max H. (hartl192)


Lesenswert?

Was macht getincrement(); eigentlich?

von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
danke für die zahlreichen Beiträge

Max H. schrieb:
> Was macht getincrement(); eigentlich?

Das ist nur ein Platzhalter, um das Problem zu verdeutlichen. Mit dem 
folgenden Prototypen: int8_t getincrement(void);

A. K. schrieb:
> Einmal mehr: Das ist
> eine Einzelfallfrage.

Soetwas habe ich schon befürchtet. Gut, die Einzelfälle sind hier 
bekannt: AVR (ATmega644) und ARM Cortex M3 (STM32F103), jeweils mit GCC.

Dieses Problemklasse müßte ja eigentlich total häufig vorkommen. Bei mir 
wird einfach eine Drehrichtung eines Motors im EEPROM abgelegt und die 
gepollte Routine recht oft in einem Interrupt aufgerufen.

Deswegen interessierte mich, ob es noch andere Lösungsansätze gibt als
 - Multiplikation explizit ausführen
 - Verzweigung
 - Aufgerufene Funktion über Funktionszeiger aufrufen und bei Bedarf 
austauschen

Viele Grüße
W.T.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Walter Tarpan schrieb:
> Deswegen interessierte mich, ob es noch andere Lösungsansätze gibt als
>  - Multiplikation explizit ausführen
>  - Verzweigung
>  - Aufgerufene Funktion über Funktionszeiger aufrufen und bei Bedarf
> austauschen

Ja gibt es. Inline-Code!!! Der Aufwand für Call und Return dürfte 
deutlich über dem für die Vorzeichenrechnung liegen. Also ein 
include-File:

#define oftgepollteroutine(vz) (vz ? getincrement() : -getincrement())

Du sparst das gesamte Stackhandling ohne Verständnisverlust.

Grüße, Kurt

von Max H. (hartl192)


Lesenswert?

1
increment=getincrement();
2
if(vorzeichen)
3
  increment=-increment;
4
merker += increment;
Wenn der µC einen Befehl zum Negieren einer Variablen hat, könnte es so 
gut gehen. Sign ist '0' wenn positiv und '1' wenn negativ.

In PIC24asm könnte das dann so aussehen:
1
mov increment,w0
2
btsc sign,#0
3
neg w0,w0
4
add merker

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Max H. schrieb:
> In PIC24asm könnte das dann so aussehen:

Nur hast du genau wie ich vorhin übersehen, dass hier mindestens 24 Bits 
gefragt sind. Das macht die Sache bei 8/16-Bittern etwas komplexer.

von Max H. (hartl192)


Lesenswert?

A. K. schrieb:
> Nur hast du genau wie ich vorhin übersehen
Sry, dann könnte es so aussehen für bis zu 32bit:
1
  mov increment_l,w0
2
  mov increment_h,w1
3
  mov sign
4
  bra z,add
5
  com w1,w1
6
  neg w0,w0
7
  addc w1,#00
8
add:
9
  add merker_l
10
  mov w1,w0
11
  addc merker_h

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.