Sehr schneller Absolutbetrag AVR

#798372
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
Gast #798515
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
Gast #798569
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
#798577
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
Gast #798597
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
Gast #798608
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!
#798652
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
Gast #798675
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.
#798682
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 ;)
Gast #798801
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

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