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
@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
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.
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?
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
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
@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?
"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
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?
> 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.
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.
@Christoph
gerade deswegen schlage ich vor, anstatt von LSR, SUB zu benutzen.
LSR wird irgendwo einen Fehler einfuehren oder man muss zig Bedingungen
auswerten.
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
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
@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.