Forum: Mikrocontroller und Digitale Elektronik Runden einer Division in ASM


von Stevko (Gast)


Lesenswert?

Hallo liebe (AVR-)ASM Freunde,

ich habe mich soeben an einem Problem festgefressen und sehe den Wald
vor lauter Bäumen nicht mehr.

Mein Problem ist eine simple Division von 8(Bit) / 8(Bit) aber
gerundet.

Mal ein Beispiel:
190:39=4,871... --> gerundet = 5 !

So, die Divisionsroutine bringt mir die 4 als Hauptergebnis und als
ganzzahliger Rest = 34. Ich finde aber, wahrscheinlich vor lauter
Rechnen, keinen Ansatz damit das Hauptergebnis 4 auf 5(wegen Rundung)
verändert wird. Im Hinterkopf habe ich noch die Formel A=A+B/2! Mit der
probiere ich jetzt schon 1 Stunde rum, jedoch ohne gescheites Ergebnis.


Also ich bin schon richtig konfus und zweifle an meinen Fähigkeiten.
Mir fehlt irgendwie der entscheidende Schritt.

Gruß
  Stevko

von romanua (Gast)


Lesenswert?

(2*190+39)/(2*39)

von Benedikt (Gast)


Lesenswert?

oder einfacher (aber nicht immer ganz so exakt, da es einen
Rundungsfehler in der Rundung gibt):

(190+39/2)/39

von Stevko (Gast)


Lesenswert?

@romanua:

Die Lösung ist zwar richtig, aber bedenke das ich mich im 8-Bit-Bereich
aufhalte.

--> 2*190 = ? = > 8Bit

Ich progamiere in ASM und meines Wissens gab es dafür eine einfache
Lösung. Irgendwas mit Schieben und Rotieren, ich habe es schon mehrmals
hier gelesen und es war so simpel, das ich es nicht notiert habe. Nach
dem Motto: "Alles klar. Das ist ja so einfach!" Doch jetzt wo ich vor
dem Problem stehe, ist es klar wie Kloßbrühe.

Gruß
  Stevko

von romanua (Gast)


Lesenswert?

Das stimmt, kannst du nur 6-bit machen. Wenn du einen Fehler in der
Rundung haben darfst, kannst Du die Methode von Benedikt mit 7-bit
einsetzen.

Nimm doch 16-bit Division. Schieben und Rotieren hoert sich nach
Multiword Arithmetic an, wenn so, dann doch mehr als 8-bit.

von romanua (Gast)


Lesenswert?

Du hast aber auch den Restbetrag, habs uebersehen.

Integer(A/B), Rst(A/B)

if B-Rst(A/B)<Rst(A/B)
   Result:=Integer(A/B)+1
   elseif
   Result:=Integer(A/B)

von romanua (Gast)


Lesenswert?

Sorry =<

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

34/39  ist größer als 0,5, also muß aufgerundet werden.

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

ein einfacher Vergleich des Rests mit der Hälfte des Divisors, die läßt
sich durch Rechtsschieben ermitteln.

von Peter D. (peda)


Lesenswert?


von romanua (Gast)


Lesenswert?

@Christoph Kessler

Was bekommt man durchs Rechtsschieben von als 39?

von romanua (Gast)


Lesenswert?

@Christoph Kessler

ich wollte sagen, das geht nur bei geraden Zahlen, wie schon Benedikt
oben schrieb.

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

Das unterste Bit fällt rechts raus, aus 39/2 wird 19 statt 19,5  Die
Rundungsgrenze liegt zwischen 19/39 (Abrunden) und 20/39 (Aufrunden).
Stimmt doch oder nicht?

von Stevko (Gast)


Lesenswert?

Guten Morgen

und Danke für die Antworten.

@Peter:
Ja das ist es was ich gesucht habe. Also probieren wir es mal aus.

 190:39=4,871...

-> a0 = 4  (Intergebnis)
   b0 = 34 (ganzzahliger Rest)
   t0 = Hilfsvariable


  mov  t0, b0    ;T = B = 34
  lsr  t0    ;T / 2 = 17
  add  a0, t0    ;A = A + B / 2 -> 21 = 4 + 17

Ne so gehts nicht.
Oder muß man das vorher addieren?

-> a0 = 190
   b0 = 39
   t0 = Hilfsvariable

  mov  t0, b0    ;T = B = 39
  lsr  t0    ;T / 2 = 19
  add  a0, t0    ;A = A + B / 2 -> 209 = 190 + 19

     Division
      geschiebe + rotiere

   Ergebnis = 5,3 -> Int_5

Aha so gehts, da konnte ich mich ja tot-probieren. Ich habe immer nach
einer Lösung hinter der Division gesucht.
Der Nachteil dieser Lösung ist aber ein Überlauf, z.B. 250:20.

Gruß
  Stevko

von romanua (Gast)


Lesenswert?

Stevko, probier noch mal mit 16:11 als Uebung, bevor du die Routine
fertig hast.

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

ich kapier immer noch nicht warum man das so kompliziert machen muß.
Wenn Divisor und Rest vorliegen, sind das doch nur drei Operationen.
Die 190 nochmal reinzunehmen ist völlig unnötig. Die "39" einmal
rechts schieben und mit der "34" vergleichen. wenn 34 wie hier größer
19 dann zum Ergebnis "4" eins addieren, sonst bleibts bei der 4

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

16/11 ist 1 Rest 5,
5 ist kleiner oder gleich INT(11/2)=5
also gerundetes Ergebnis = 1

von romanua (Gast)


Lesenswert?

@Christoph

habe nicht verstanden, wo du gleich mitreinnimmst zu "kleiner" oder
zu "groesser"

Dann dieses Beispiel:

6/4 ist 1 Rest 2

2 ist kleiner oder gleich INT(4/2)=2

also gerundetes Ergebnis = 1

stimmts?

von Peter D. (peda)


Lesenswert?

"ich kapier immer noch nicht warum man das so kompliziert machen
muß."

Was ist denn daran so kompliziert ?

q = (a + b/2) / b;


Aber bei Dir sinds sogar noch 2 Schritte mehr:

q, rest = a / b, a % b;

if( rest * 2 > b )
  q++;


Peter

von romanua (Gast)


Lesenswert?

Peter,

Christophs 2 extra Schritte sollten einen Ueberlauf verhindern, wenn
man 8-bit eine ASM (int+rest) Routine hat, sind aber rechnerisch
falsch.

Meine 2 extra Schritte verhindern den Ueberlauf und sind rechnerisch
korrekt, meine ich

if B-Rst(A/B)=<Rst(A/B)
   Result:=Int(A/B)+1
elseif
   Result:=Int(A/B)

Hat jemand ein Beispiel, wo es ein falsch abgerundetes Ergebnis
liefert?

von Karl heinz B. (kbucheg)


Lesenswert?

> Was ist denn daran so kompliziert ?
>
> q = (a + b/2) / b;

Na ja, das kann kompliziert werden, wenn a + b/2
einen Überlauf produziert.
Was man noch untersuchen müsste ist, wie jetzt ein
mögliches negatives Vorzeichen von a oder b (oder beiden)
da mit eingeht und sich auswirkt.

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

Das mit 6/4 stimmt, ich muß doch vor dem Halbieren 1 addieren,
entsprechend einer Addition von 0,5 beim dezimalen Runden, das geht mit
INC Divisor am einfachsten, solange er unter 255 bleibt.
Für die 6/4 muß dann "kleiner als" bzw. "größer oder gleich" die
Grenze bilden, sonst stimmts immer noch nicht.

von romanua (Gast)


Lesenswert?

@Christoph

gerade deswegen schlage ich vor, anstatt von LSR, SUB zu benutzen.


LSR wird irgendwo einen Fehler einfuehren oder man muss zig Bedingungen
auswerten.

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

und sogar mit Divisor 255 klappts, der INC setzt das Carryflag, beim
Halbieren durch rechtsschieben kommt das ins MSB runter, egibt
$80=128.
es ist auf keinen Fall mehr 16Bit-Arithmetik nötig, wenn die
eigentliche Division erledigt ist.
Von negativen Zahlen war in der Aufgabe nicht die Rede, mit
Zweierkomplementdarstellung wird alles etwas komplizierter

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

INC Divisor
LSR Divisor
CMP Rest,Divisor
BRLT Fertig
INC Ergebnis
Fertig:

von Stevko (Gast)


Lesenswert?

So, habe jetzt wieder mal ein wenig Zeit. Mein Dank geht an Alle die
hier mitwirken. Wie Ihr seht ist es nicht so einfach gewesen aber mehr
Köpfe = mehr Ideen!

Der Vorschlag von Christph sieht doch ganz passabel aus. Werde Ihn
heute Abend mal testen. Jedenfall ist das Problem mit dem Überlauf
vorläufig vom Tisch.

Gruß
  Stevko

von romanua (Gast)


Lesenswert?

@Divisor=r1
@Difference=r1
@Rest=r2
@Ergebnis=r3

SUB Divisor, Rest     ;Difference=Divisor-Rest
CMP Rest,Difference   ;Set Flags
BRLT Fertig           ;exit if Difference > Rest
INC Ergebnis
Fertig:

Ich werd verrueckt noch einmal. Das gehts doch schneller und richtiger
als mit rechtsschieben.

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.