PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 2xbit dividieren durch 2x8bit



Philipp83
20.03.2006, 17:38
Nabend liebe Gemeinde!!

Ich habe lange gesucht, aber leider nichts gefunden :-(.
Ich möchte in Assembler eine Zahl die in
r16 und r17 steht, durch eine zahl die in r18 und r19 steht teilen.
z.b. 60000/20000

Ich habe einfach keine ahnung wie ich da überhaupt vorgehen muss.
Finde auch leider nichts dazu.
mit welchem register muss ich was machen?

mfg, Philipp

DANKESCHÖN!!!!!!!!!

SprinterSB
20.03.2006, 17:41
Schon mal Rechnen mit 3 Registern (https://www.roboternetz.de/phpBB2/viewtopic.php?t=17671) gelesen? Das ist fast das gleiche Thema.

Philipp83
20.03.2006, 17:48
:-)

Ja, ich bin sogar der Verfasser des Rechnen mit 3 Registern.
Allerdings wurde es immer mit sehr viel code erklärt, was mich doch
verwirrt hat.
Habe daher immernoch das gleiche Problem mit rechnen von Dualzahlen
die über 1 Register hinausgehen.

AlexAtRobo
20.03.2006, 18:09
Ist dir lieber, wenn wir dir code ohne Erklärung schicken? Ich denke, dort wurde alles ausführlich in verschiedenen Varianten erklärt.
lg
Alex

Philipp83
20.03.2006, 18:16
Hi Alex

erst nochmal vielen vieln Dank für dir Mühe!!!
Nein, das bei dem Code Erklärungen dabei waren war super,
nur konnte ich die langen Code`s nicht ganz nachvollziehen.
Ist es vielleicht bei 2x8bit / 2x8bit leichter zu verstehen?
Ich möchte nämlich gerne einen Tacho für mein Hamsterrad programmieren :-). der Kilometerzähler davon funktioniert schon :-).

Gruß, Philipp

Philipp83
20.03.2006, 20:20
Es wäre auch sehr hilfreich wenn ich wüsste wie man das ganze
schriftlich auf dem Papier realisiert.

Kennt ihr vielleicht eine Adresse wo dies erklärt ist?

Danke!!

SprinterSB
21.03.2006, 09:20
Also auf Papier fängst du am besten mit normaler Division an, wie du sie in der Grundschule gelernt hast. Einfach mit Dezimalzahlen. Das passende Untereinanderschreiben ist ein Shift im Dezimalsystem um x Stellen, also Multiplikation mit 10^x.

Mit Binärzahlen geht es genauso... Ein Shift (Schieben) um x Stellen ist da ne Multiplikation mit 2^x.

SprinterSB
21.03.2006, 09:41
Beispiel:

1111
----
110

Der Nenner wird erst nach links geschoben, bis das obere Bit mit dem Zähler übereinstimmt:

1111 Q=0
----
1100

Der Nenner ist kleiner als der Zähler, passt also genau 1x rein und kann abgezogen werden.
Aber wir ziehen nicht den Nenner ab, sondern 2^1 mal den Nenner, weil wir ihn einmal
nach links geschoben haben. Diese 2 wird zum Quotenten Q dazugezählt,
also Bit 1 von Q gesetzt


0011 Q=10
----
1100

Der Nenner kann jetzt nicht mehr reinpassen (wegen Zweiersystem) und wird 1 nach rechts geschoben

0011 Q=10
----
110

er passt nicht rein, Bit 0 von Q bleibt also 0

Bei einer Ganzzahldivision sind wir schon fertig. Der Quotient ist 2 und der Rest ist 3 (Zähler)
Test: 15 = 2*6+3

Wenn wir aber weitermachen:

0011 Q=10
----
11

Passt der Nenner wieder rein. Wir sind jetzt bei Bit -1 von Q, also bei der ersten Nachkommastelle.
Nenner abziehen und Bit -1 von Q setzen, bzw 2^(1/2) zu Q addieren:

0000 Q=10.1
----
11

Wir sind fertig, weil der Rest 0 ist: Q=2.5
Test: 15 = 2.5*6

Philipp83
22.03.2006, 15:55
Dank für das Bsp,

Aber ich dachte eigentlich an eine Schriftl. Lösung von 2X8 / 2X8 Bit.
z.b.

11101010, 01100000 = 60000
------------------------------------
10011100, 00100000 = 20000

Aus der Division der Beiden Zahlen (2x8 Bit / 2x8 Bit) sollte 3 rauskommen.

Nur wie stelle ich das am besten an?


Trotzdem vielen vielen dank für eure Mühen !!!!!!!

SprinterSB
22.03.2006, 16:02
Für mehr bits geht es doch genauso. Wenn du das kleine Beispiel verstanden hast, wirst du es auch mit grösseren Zahlen verstehen.

20000 = 01001110 00100000, vielleicht war das dein Fehler?

Philipp83
22.03.2006, 16:16
Hast zwar recht, aber das war nicht der Fehler :-(

Hmm,

Naja..... vielleicht bekomme ich ja auch nochmal einen Geistesblitz.
Vielleicht sollte ich auch einfach bei meinen Sprachen Basic,C bleiben.
War zwar fest entschlossen was Assembler angeht, was auch programmmäßig
alles gut klappt, aber diese rechnerei kapiere ich einfach irgendwie nicht.

mfg, Philipp

SprinterSB
22.03.2006, 16:25
R = 11101010 01100000 = 60000
------------------------- Q = 0
N = 01001110 00100000 = 20000

N schieben, so daß das höchste Bit stimmt:

R = 11101010 01100000
----------------- Q = 0
2*N = 10011100 01000000

abziehen, da kleinergleich

R = 01001110 00100000
----------------- Q = 10
2*N = 10011100 01000000

Nenner nach rechts schieben

R = 01001110 00100000
------------------ Q = 10
1*N = 01001110 001000000

abziehen, da kleinergleich

R = 00000000 000000000
------------------ Q = 11
1*N = 01001110 001000000

Fertig, da Rest=0 bzw Nenner am rechten Anschlag

Q = 11 (=3)

Philipp83
23.03.2006, 16:14
Hallo liebe Leute

Ich habe zwar jetzt verstanden wie das ganze auf dem papier funktioniert,
nur das in assembler richtig umzusetzen... Naja :-)

Auf alle fälle VIELEN DANK an alle! Aber auch besonders an Alex, der ein so gut funktionierendes proggi gepostet hat.
Das zu verstehen dauert zwar glaub ich noch etwas (avrstudio zeigt die register ja leider nicht in binär an).
Eigentlich kann ich das nicht sehr gut mit mir vereinbaren etwas in mein Programm aufzunehmen was ich nicht 100% verstehe,
Aber nun gut.

Sagt mal, wie lange programmiert ihr schon in assembler das euch sowas keine Probleme macht?

mfg, philipp

Philipp83
23.03.2006, 16:17
STOP!!

Auch Georg darf nicht zu kurz kommen!!!!
Ist echt super nett das du mir die einzelnen Schritte ausführlich gezeigt hast!

AlexAtRobo
24.03.2006, 08:32
Hallo Phillipp,

du kannst im AVR Studio auch die Register Binär anzeigen. Dazu gibt es ein eigenes Fenster zum Registeranzeigen. Dass kannst du auch auf Binär umstellen, dann ist es schöner zum nachvollziehen. Mußt mal schauen, ich hab jetzt auf diesem rechner grad kein Studio drauf. Geht aber auf jeden Fall.

lg

Alex

AlexAtRobo
24.03.2006, 08:44
Noch was:

cp rd1uh, rd2h
brcs div3
cp rd1ul,rd2l ; Divisionsergebnis 1 oder 0?
brcs div3 ; Überspringe Subtraktion, wenn kleiner

Und hier ist noch ein Fehler drinnen. Es wird bei der ersten Abfrage nur verzweigt, wenn rd1uh < rd2h ist. Wenn beide gleich groß sind, ist es auch noch ok. Aber wenn rd2h > rd1uh ist, muß sofort verzweigt werden.

Der richtige Vergleich ist von Georg geschrieben worden.
cp rd1ul, rd2l
cpc rd1uh, rd2h

Wie lange schon Assembler? Naja, am AVR erst 2 Jahre - aber es ist einfach geil, wenn man über die Serielle Schnittstelle X/Y/Z x 2Bytes übergibt, dann die unterschiedlichen Steigungen der Geraden im AVR Berechnet, und 3 Schrittmotoren zeitgleich unterschiedlich schnell ansteuert dass alle Zeitgleich am Zielpunkt ankommen. Und das mit weniger als 600 Zeilen Assembler. Und es ginge noch mit weniger... Beschleunigungsrampen und Bremsrampen sind auch noch drinnen ;-). Und dem Ding ist immer noch langweilig...

Was nicht heißt das es nicht mit Winavr C auch genauso gegangen wäre.

Übrigens war die Division auch für mich am Anfang mühsam, aber mit der Zeit durchschaut man es dann schon.

lg

Alex

SprinterSB
24.03.2006, 13:22
Hier noch eine sehr effiziente Divisionsroutine für zwei 16-Bit-Werte.
Sie braucht nur 7 Register und 18 Instruktionen.
Ausserdem berechnet sie auch den Rest der Division.


; Input
; r25:r24 = Zähler
; r23:r22 = Nenner

; Output
; r25:r24 = Quotient
; r27:r26 = Rest

; Verwendete Register:
; r21-r27

div16:
; Ergebnis auf 0, Carry löschen
clr r26
sub r27, r27
; 17 Bits werden rotiert (16 Bits-Wert und Carry)
ldi r21, 17
rjmp div16_start

div16_loop:
; Zähler nach links rotieren (Bits kommen aus r25:r24)
rol r26
rol r27
; Vergleich gegen Nenner
cp r26, r22
cpc r27, r23
brcs div16_start
; Abziehen, wenn kleinergleich
sub r26, r22
sbc r27, r23

div16_start:
; Hier entsteht das Komplement des Ergebnisses
; C=0: es wurde abgezogen
; C=1: es wirde nicht abgezogen
rol r24
rol r25
dec r21
brne div16_loop
; fertig
; Bits des Ergebnis müssen noch invertiert werden
com r24
com r25
ret


Die Routine ist von avr-gcc.