Forum: Mikrocontroller und Digitale Elektronik [Assembler] aufrunden


von Neuling (Gast)


Lesenswert?

Hallo Leute,

ich beschäftige mich seit kurzem mit dem AVR Assembler und bin da auf 
ein Problem gestoßen, bei dem ich nicht so recht weiß, wie ich es lösen 
soll.
Ich versuche mein Problem mal anhand eines Minimalbeispiels zu 
erläutern.

Über den USART bekomme ich einen vorzeichenbehafteten 8bit Wert, den ich 
durch eine Zweierpotenz teilen und das Ergebnis aufrunden möchte. Da ich 
nur durch Zweierpotenzen teile, hab ich mir gedacht, ich verwende den 
Shift Operator (arithmetical right shift), um Zyklen zu sparen. Also 
angenommen, ich habe den Wert 9 im Register r16 stehen und möchte diesen 
durch 4 dividieren. Dann würde ich schreiben:
1
;in r16 steht der Wert 9
2
asr r16
3
asr r16
4
;nach den beiden Shift Befehlen steht in r16 der Wert 2

Nun möchte ich aber, dass der Wert der Division ( 9/4 = 2.25) immer 
aufgerundet wird. In meinem Fall sollte also auf 3 aufgerundet werden. 
Die Frage ist nur, wie mach ich das? Ich hab schon versucht, auf ein 
gesetztes Carry Flag zu überprüfen und dieses dann zu meinem Ergebnis zu 
addieren, doch das klappt leider auch nicht so ganz. Hat da jemand einen 
Tipp wie man das elegant lösen könnte? Ich glaub, ich steh da gerade 
etwas auf dem Schlauch...

von spess53 (Gast)


Lesenswert?

Hi

>asr r16

Mit asr solltest vorsichtig sein. Das ist für vorzeichenbehaftete 
Zahlen. Für Zahlen >127 könnte es unangenehme Überraschungen geben.

>Nun möchte ich aber, dass der Wert der Division ( 9/4 = 2.25) immer
>aufgerundet wird. In meinem Fall sollte also auf 3 aufgerundet werden.

[avrasm]
subi r16,-3
lsr r16
lsr r16
[{avrasm]

sollte dein Problem lösen.

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Sollte so aussehen:
1
subi r16,-3   ; +3
2
lsr r16
3
lsr r16

MfG Spess

von Neuling (Gast)


Lesenswert?

Hallo,

spess53 schrieb:
> Mit asr solltest vorsichtig sein. Das ist für vorzeichenbehaftete
> Zahlen. Für Zahlen >127 könnte es unangenehme Überraschungen geben.

Da ich vom USART einen vorzeichenbehafteten 8bit Wert bekomme, wäre das 
dann doch genau das richtige, oder? Es gibt übrigens eine Routine, die 
überprüft, dass sich die Zahl x in folgendem Bereich befindet: -127 <= x 
<= 127

spess53 schrieb:
> Sollte so aussehen:
> subi r16,-3   ; +3
> lsr r16
> lsr r16

Das funktioniert für positive Zahlen wunderbar, doch wenn im Register 
r16 eine negative Zahl steht, dann funktioniert es nicht mehr. Das war 
auch der Grund, warum ich zu asr tendiert habe. Man könnte das jetzt 
natürlich so lösen, dass man für positive Zahlen lsr und für negative 
Zahlen asr verwendet, doch das wäre ja ziemlich ineffizient, oder?

PS: Könntest du vielleicht auch noch erklären, warum du -3 subtrahierst? 
Es funktioniert zwar, aber mir ist irgendwie nicht ganz klar, warum das 
so ist.

von (prx) A. K. (prx)


Lesenswert?

Neuling schrieb:
> Das funktioniert für positive Zahlen wunderbar, doch wenn im Register
> r16 eine negative Zahl steht, dann funktioniert es nicht mehr. Das war
> auch der Grund, warum ich zu asr tendiert habe.

Was verstehst du im Negativen genau unter "aufrunden"? Soll -3/2 nun -1 
sein (mathematisch aufgerundet) oder -2 (betragsmässig aufgerundet)?

Die 3 (Nenner - 1) werden vorher addiert, weil ASR stets mathematisch 
abrundet. Mit dieser Addition wird aufgerundet.

Man subtrahiert -3, weil der AVR keine Konstante addieren kann, nur 
subtrahieren.

von spess53 (Gast)


Lesenswert?

Hi

>Da ich vom USART einen vorzeichenbehafteten 8bit Wert bekomme, wäre das
>dann doch genau das richtige, oder?

In dem Fall ja.

>PS: Könntest du vielleicht auch noch erklären, warum du -3 subtrahierst?
>Es funktioniert zwar, aber mir ist irgendwie nicht ganz klar, warum das
>so ist.

Weil es keinen Befehl gibt, der eine Konstante zu einem Register 
addiert. Nur Subtraktion. Und ein subi rxy, -x entspricht einem (nicht 
vorhandenem) addi rxy, x.

MfG Spess

von Neuling (Gast)


Lesenswert?

A. K. schrieb:
> Was verstehst du im Negativen genau unter "aufrunden"? Soll -3/2 nun -1
> sein (mathematisch aufgerundet) oder -2 (betragsmässig aufgerundet)?

Oh, stimmt, das hätte ich besser spezifizieren sollen.
Ich meine mathematisch aufrunden. Also -3/2 soll zu -1 werden.

A. K. schrieb:
> Die 3 (Nenner - 1) werden vorher addiert, weil ASR stets mathematisch
> abrundet. Mit dieser Addition wird aufgerundet.

Kann ich mir das folgendermaßen vorstellen:

Die Zahl 9 wird in Binärdarstellung durch 00001001 repräsentiert.
Wenn ich die Zahl 9 nun um 2 nach rechts shifte (also durch 4 
dividiere), dann erhalte ich 00000010, was 2 im Dezimalsystem 
entspricht. Wie man sieht, wird hier das letzte Bit rausgeschoben und 
hat keinen Einfluss auf das Ergebnis. Wenn ich aber vorher 3 addiere, 
dann hat das letzte Bit noch einen Einfluss auf das Ergebnis (es wird 
also aufgerundet). Ist das korrekt?

Wenn ich also statt 2x nach rechts, 3x mal nach rechts shiften würde, 
dann müsste ich vorher 6 addieren. Also:
subi r16,-6

Stimmt das?

von Dieter W. (dds5)


Lesenswert?

Neuling schrieb:
> Wenn ich also statt 2x nach rechts, 3x mal nach rechts shiften würde,
> dann müsste ich vorher 6 addieren. Also:
> subi r16,-6
>
> Stimmt das?

Fast.
Du musst immer (Divisor - 1) addieren, im geschilderten Fall also 7.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Neuling schrieb:
> Oh, stimmt, das hätte ich besser spezifizieren sollen.
> Ich meine mathematisch aufrunden. Also -3/2 soll zu -1 werden.

Dann passt der Vorschlag von spess53, wenn du die LSR durch ASR ersetzt. 
Eine Fallunterscheidung zwischen positiven und negativen Zahlen brauchst 
du nicht.

von Neuling (Gast)


Lesenswert?

Dieter Werner schrieb:
> Du musst immer (Divisor - 1) addieren, im geschilderten Fall also 7.

Danke, hab mir das ganze jetzt nochmal im ausgeschlafenen Zustand 
durchgedacht und ich versteh's jetzt :)


Danke auch an spess53, A.K. und Yalu X.!

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.