Unterschied zweier Variablen

#367620
Lesenswert?

"Hmmm...dürfte wohl bei sehr grosszügigem Einsatz einiges an
Rechenleistung kosten..."


Nö, überhaupt nicht.

Is ja nur ein Test und ne Subtraktion.
Aufm ATMega88 bei 20MHz unter WINAVR dauerts max 0,3µs:
1
c = a > b ? a - b : b - a;
2
  5c:   68 17           cp      r22, r24
3
  5e:   18 f4           brcc    .+6             ; 0x66 <test+0xa>
4
  60:   86 1b           sub     r24, r22
5
  62:   68 2f           mov     r22, r24
6
  64:   01 c0           rjmp    .+2             ; 0x68 <test+0xc>
7
  66:   68 1b           sub     r22, r24

Ist bestimmt 100 mal schneller als in Java.


Peter
Gast #367621
Lesenswert?

Wieder einer der glaubt, dass etwas, das sich kurz schreibt auch nicht
lange dauern kann und sich dann wundert, dass ein klitzekleines printf
oder so (am besten noch in einer ISR) das ganze System abschießt...

Aber im Ernst: Ich kenne mich mit Java nicht sonderlich aus, denke
aber, dass hinter der Schreibweise 'Math.abs(a - b)' im Prinzip nix
anderes (zumindest nicht viel anderes) steckt als das, was Peter
gepostet hat. Und kürzer gehts nun wirklich nicht!
#367628
Lesenswert?

@Karl Heinz

"#define ABS( a )  (a) < 0 ? (a) : -(a)"


Und schon bist Du in die Falle getappt !

a und b sind vom Typ uint8_t, also unsigned und damit ist der Ausdruck
(a) < 0 immer falsch.

Das AVR-GCC abs-Macro erweitert deshalb auf signed int, macht dann erst
die Subtraktion, dann den Betrag und schmeißt das High-Byte wieder weg.
Deshalb dauert es auch länger.
Ob das der AVR-GCC nur zufällig so macht wie gewünscht, weiß ich
nicht.
abs() auf unsigned klingt jedenfalls irgendwie sinnlos.

Daher finde ich a > b ? für unsigned Werte besser lesbar als abs(). Und
ich habe die Garantie, daß er genau das macht, was ich will.


Peter
Gast #367630
Lesenswert?

Hallo

Könnte das mit dem unsigned mein Problem sein?

uint8_t d = (ADCH > gbc_ee_buffer) ? (ADCH - gbc_ee_buffer) : 29;

Dieser Ausdruck ist immer falsch, d.h. ich kriege immer 29... (Obwohl
es mehr als nur schlüssige Hinweise gibt, dass sowohl ADCH wie auch
gbc_ee_buffer mal grösser sind.)

Was ich meinte wegen langsam: Ich habe auf ne Lösung gehofft à la
'subtrahieren' und dann irgend wo vielleicht noch ein Bit drehen oder
so... Hoffentlich hält ihr mich jetzt nicht für total naiv ;-) - ich
sollte mich aber echt mal mit der grundlegenden Art und Weise, wie
Zahlen gespeichert und verarbeitet werden, befassen! ^^

Gruss

Michael
Gast #367631
Lesenswert?

Schreib statt der 29 mal ne 42 rein, vielleicht klappts dann besser;-)

Im Ernst: Man kann es sso versuchen, wie man es in Assembler machen
kann: Einfach ins blaue hinein subtrahieren. Wenn was negatives
rauskommt, gibts nen Underrun in der Zielvariable. Dann das
Zweierkomplement aufdröseln (MSB checken, wenn gesetzt, dann
Bitkomplement bilden und eins dazuaddieren) und --Zack-- hat man den
Betrag.
Gast #367634
Lesenswert?

> Ich habe auf ne Lösung gehofft à la 'subtrahieren' und dann irgend
> wo vielleicht noch ein Bit drehen oder so...

Sowas in der Art geht schon, aber wird dann schwierig in C. Wenn's dir
auf Geschwindigkeit und Codegröße ankommt, wird's wohl am besten
Assembler sein. Etwa sowas wie das müßte gehen:

    sub r16, r17
    brsh next
    neg r16
next:
Gast #367639
Lesenswert?

Um noch den Unterschied zu erläutern: Peter geht davon aus, daß nach der
Subtraktion a (wenn man es als vorzeichenbehaftet interpretiert) negativ
ist, wenn es vorher kleiner als b war. Diese Annahme ist aber nur dann
in jedem Fall korrekt, wenn a und b auch tatsächlich
vorzeichenbehaftete Zahlen sind. Für vorzeichenlose Zahlen muß der
Vergleich anders aussehen. Deshalb enthält mein Asssembler-Code auch
ein brsh (vorzeichenloser Vergleich) und kein brge
(vorzeichenbehafteter Vergleich).

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