mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Sehr schneller Absolutbetrag AVR


Autor: Lukas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich suche eine Möglichkeit von einem vorzeichenbehafteten 8Bit Wert 
möglichst schnell den Absolutbetrag in C zu berechnen.
Gibt es da irgendwelche Tricks?

Autor: 6639 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der C Compiler macht das sicher schon optimal : abs()

Autor: Dirk Broßwick (sharandac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Feststellen ob positiv oder negativ anhand des MSB, und wenn negativ 
2komplement bilden, und fertig.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Lukas (Gast)

>Ich suche eine Möglichkeit von einem vorzeichenbehafteten 8Bit Wert
>möglichst schnell den Absolutbetrag in C zu berechnen.
>Gibt es da irgendwelche Tricks?

Keine Ahnung. Was spricht gegen

int8_t abs(int8_t data) {
  if (data >=0) return data
  else return -data;
} 

Das wird schon recht gut in ASM umgesetzt.

MFG
Falk

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die "Geradeausmethode" kann unmöglich die schnellste sein. Wenn dann 
schon
#define abs(data) (data >= 0 ? data : -data)

Womit schon mal der Funktionsaufruf gespart wird.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Entwickler (Gast)

>Womit schon mal der Funktionsaufruf gespart wird.

Schonmal was von inline Funktionen gehört?

MfG
Falk

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab' nix von 'inline' gelesen. Die Idee ist gut.

Autor: Fred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

obwohl ich sehr viel Assembler benutze (auch zusammen mit C), stehe ich 
zugegebenermaßen mit dem Inline Assembler immer noch etwas auf 
Kriegsfuß. Deshalb hier zur Diskussion:

volatile int8_t value;
value=-100;

asm volatile(
   "tst %0"     "\n\t"
   "brpl L_%="  "\n\t"
   "neg %0 "    "\n\t"
   "L_%=:"
   : "=r" (value) :
);
// value weiterverarbeiten

Der Compiler hat es so gemacht:
  LDI     R24,0x9C         Load immediate
  STD     Y+1,R24          Store indirect with displacement
  TST     R24              Test for Zero or Minus
  BRPL    PC+0x02          Branch if plus
  NEG     R24              Two's complement
  STD     Y+1,R24          Store indirect wi

Grüße

Fred

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Fred S. (fredhs)

>Kriegsfuß. Deshalb hier zur Diskussion:

Das ist optimal. Nun schreibs mal in C hin und staune ;-)
Optimierung aber einschalten.

MfG
Falk

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entwickler wrote:
> #define abs(data) (data >= 0 ? data : -data)

#define abs(data) ((data) >= 0 ? (data) : -(data))

Makro-Argumente unbedingt klammern, sonst geht abs(1+x) böse schief.

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Test und Sprung könnte man wohl noch zusammenfassen, etwas so:

    SBRC R24,7
    NEG R24

Autor: Fred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Falk,

guter Tipp für ein (nicht gerade sehr positives!) Erstaunen; hier für 
alle (Compiler Optimierung -O3) -- ich musste die nächsten 
Programmzeilen mit reinschreiben; den Grund seht Ihr hier:

volatile int8_t value=-100;
   LDI     R24,0x9C         Load immediate
   STD     Y+1,R24          Store indirect with displacement
if (value<0) value=-value;
   LDD     R24,Y+1          Load indirect with displacement
   SBRC    R24,7            Skip if bit in register cleared
!  RJMP    PC+0x0009        Relative jump
for (uint8_t i=n; i>0; i--) {
   TST     R25              Test for Zero or Minus
   BREQ    PC+0x0B          Branch if equal
   MOV     R24,R25          Copy register
PORTB&= ~(1<<PB0); // PB0=0 for one cycle
   CBI     0x18,0           Clear bit in I/O register
PORTB |=  1<<PB0;   // PB0=1 again
   SBI     0x18,0           Set bit in I/O register
   SUBI    R24,0x01         Subtract immediate
   BRNE    PC-0x03          Branch if not equal
   RJMP    PC+0x0005        Relative jump
!  LDD     R24,Y+1          Load indirect with displacement
   NEG     R24              Two's complement
   STD     Y+1,R24          Store indirect with displacement
!  RJMP    PC-0x000B        Relative jump

Die RJMPs (mit '!' markiert) sind ja ein echter Witz!

Viele Grüße

Fred

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Fred S. (fredhs)

>guter Tipp für ein (nicht gerade sehr positives!) Erstaunen; hier für
>alle (Compiler Optimierung -O3) -- ich musste die nächsten
>Programmzeilen mit reinschreiben; den Grund seht Ihr hier:

Und wo ist der absolute Betrag im C Quelltext?

MFG
Falk

Autor: Fred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Falk,

sollte
  if (value<0) value=-value;
ein Problem darstellen -- oder meintest Du abs()??

Gruß

Fred

Autor: Fred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falls dem so war, hier der Code:
volatile int8_t value=-100;
  LDI     R24,0x9C         Load immediate
  STD     Y+1,R24          Store indirect with displacement
value=abs(value);
  LDD     R24,Y+1          Load indirect with displacement
  CLR     R25              Clear Register
  SBRC    R24,7            Skip if bit in register cleared
  COM     R25              One's complement
  SBRC    R25,7            Skip if bit in register cleared
! RJMP    Sprungziel        Relative jump
Rückwärts:
  STD     Y+1,R24          Store indirect with displacement
//blabla
Sprungziel:
  COM     R25              One's complement
  NEG     R24              Two's complement
  SBCI    R25,0xFF         Subtract immediate with carry
  RJMP    Rückwärts        Relative jump

Immer noch ein fröhliches Gehüpfe!

Gruß

Fred

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

In Assembler

  and $80

und fertig.

MfG Spess

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Entschultigung. Bitte vergessen !

MfG Spess

Autor: Fred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Spess,

das geht nicht.

       0xff & 0x80 => 0x80; also -1 & 0x80 => -128

Selbst wenn Du value & 0x7f gemeinst haben solltest, klappt es nicht:

     0xff & 0x7f => 0x7f; also -1 & 0x7f => 127

Gruß

Fred

P.S. Spess, Du warst schneller!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Fred S. (fredhs)

>Immer noch ein fröhliches Gehüpfe!

Muss man im Kontext sehen. Zeig mal deinen C-Quelltext. Die volatile 
Variable ist doch zum Testen und damit sie nicht wegoptimiert wird. Das 
ist unrealistisch, weil somit der Compiler kaum Register nutzen kann.

MFG
Falk

Autor: Fred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Falk,

> Muss man im Kontext sehen. Zeig mal deinen C-Quelltext. Die volatile
> Variable ist doch zum Testen und damit sie nicht wegoptimiert wird.

Klar. Quelltext war nichts als:

   volatile int8_t value=-100;
   value=abs(value);
   // anderer Code

Sieht allerdings im folgenden Beispiel (wieder mit -O3) keineswegs 
besser aus:

   void test(int8_t n){
     int8_t i,j;
     i=n;
     j=abs(i);
//blabla
   }

Dein Tipp war gut: Ich werde in Zukunft noch öfter nachsehen, was der 
Compiler da so treibt!

Gruß

Fred

P.S. Ich fürchte allerdings, dass wir hier stark von der Frage des OP 
abgekommen sind, die ja inzwischen beantwortet ist.

Autor: Philipp F. (nerdture)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also das (meiner Meinung nach) schnellste:

Du fängst ja anschließend irgendetwas mit deinem Absolutbetrag an. Und 
diesen Teil schreibst du einfach zweimal. Einmal mit der Annahme dass 
die Zahl schon positiv ist und einmal, mit der Annahme dass sie negativ 
ist.

Alles was du dann brauchst ist ein einziger Vergleich und Branch zu dem 
jeweiligen Code-Teil. Natürlich ist der Programmcode dann aufgeblasen, 
aber wenn's dir wirklich nur um die Geschwindigkeit geht, kannst du so 
alles rausholen ;)

Autor: +-0 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was spricht gegen ein Makro, welches eine inline-asm anweisung erzeugt, 
die das Argument und Ergebnis in einem Register erwartet und zurückgibt 
und die einfach nur aus
sbrc x, 7
neg x
besteht?

Ich denke, das ganze lade-speicher kramsel vom gcc kann man eh nicht 
groß verändern. Habe auch festgestellt, dass der gcc durch bestimmte 
"programmiertechnische" Kniffs dazu gebracht werden kann, tatsaechlich 
nur etwa doppelt so großen Code zu erzeugen, wie es ein Mensch mit viel 
Asmerfahrung in ASM kann.

grüße

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.