Forum: Mikrocontroller und Digitale Elektronik Sehr schneller Absolutbetrag AVR


von Lukas (Gast)


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?

von 6639 (Gast)


Lesenswert?

Der C Compiler macht das sicher schon optimal : abs()

von Dirk B. (sharandac)


Lesenswert?

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

von Falk B. (falk)


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

1
int8_t abs(int8_t data) {
2
  if (data >=0) return data
3
  else return -data;
4
}

Das wird schon recht gut in ASM umgesetzt.

MFG
Falk

von Entwickler (Gast)


Lesenswert?

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

Womit schon mal der Funktionsaufruf gespart wird.

von Falk B. (falk)


Lesenswert?

@ Entwickler (Gast)

>Womit schon mal der Funktionsaufruf gespart wird.

Schonmal was von inline Funktionen gehört?

MfG
Falk

von Entwickler (Gast)


Lesenswert?

Ich hab' nix von 'inline' gelesen. Die Idee ist gut.

von Fred S. (Gast)


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

von Falk B. (falk)


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

von Andreas S. (andreas) (Admin) Benutzerseite


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.

von Entwickler (Gast)


Lesenswert?

Den Test und Sprung könnte man wohl noch zusammenfassen, etwas so:

    SBRC R24,7
    NEG R24

von Fred S. (Gast)


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

von Falk B. (falk)


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

von Fred S. (Gast)


Lesenswert?

Hi Falk,

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

Gruß

Fred

von Fred S. (Gast)


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

von Spess53 (Gast)


Lesenswert?

Hi

In Assembler

  and $80

und fertig.

MfG Spess

von Spess53 (Gast)


Lesenswert?

Hi

Entschultigung. Bitte vergessen !

MfG Spess

von Fred S. (Gast)


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!

von Falk B. (falk)


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

von Fred S. (Gast)


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.

von Philipp F. (nerdture)


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 ;)

von +-0 (Gast)


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
1
sbrc x, 7
2
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

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.