AVR-GCC/ARM-GCC: Vorzeichen effizient implementieren

OP #3536783
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.
#3536796
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!).
OP #3536798
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?
(Firma: KHTronik) #3536807
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
#3536840
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.
OP #3536855
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.
(Firma: KHTronik) #3536912
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
#3536943
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

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