Ich suche eine Möglichkeit von einem vorzeichenbehafteten 8Bit Wert möglichst schnell den Absolutbetrag in C zu berechnen. Gibt es da irgendwelche Tricks?
Feststellen ob positiv oder negativ anhand des MSB, und wenn negativ 2komplement bilden, und fertig.
@ 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
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.
@ Entwickler (Gast)
>Womit schon mal der Funktionsaufruf gespart wird.
Schonmal was von inline Funktionen gehört?
MfG
Falk
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
@ Fred S. (fredhs)
>Kriegsfuß. Deshalb hier zur Diskussion:
Das ist optimal. Nun schreibs mal in C hin und staune ;-)
Optimierung aber einschalten.
MfG
Falk
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.
Den Test und Sprung könnte man wohl noch zusammenfassen, etwas so: SBRC R24,7 NEG R24
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
@ 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
Hi Falk, sollte if (value<0) value=-value; ein Problem darstellen -- oder meintest Du abs()?? Gruß Fred
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
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!
@ 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
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.
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 ;)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.