Wo kann ich Soft-Multiplikation und Division Algorithmen finden?
-
24-09-2019 - |
Frage
Ich arbeite an einem Mikro-Controller ohne Hardware-Multiplikation und Division. Ich brauche Software-Algorithmen für diese grundlegenden Operationen zu kochen, die eine gute Balance aus kompakter Größe und Effizienz sind. Mein C-Compiler-Port wird diese algos beschäftigt, nicht die der C-Entwickler selbst.
Mein Google-Fu so weit ist Aufdrehen meist Lärm zu diesem Thema.
Kann jemand Punkt mich zu etwas informativ? Ich kann add / sub und Schiebebefehle verwenden. Suche in einer Tabelle basiert algos könnte auch Arbeit für mich, aber ich bin ein wenig besorgt über so viel in die Back-End-Compiler pauken ... um, so zu sprechen.
Lösung
Hier ist eine einfache Multiplikation Algorithmus:
-
Starten Sie mit Bit ganz rechts Multiplikator.
-
Wenn das Bit in dem Multiplizierer 1 ist, fügen Sie Multiplikand
-
Shift-Multiplikanden mit 1
-
Zum nächsten Bit in Multiplikator und gehen Sie zurück zu Schritt 2.
Und hier ist ein Divisionsalgorithmus:
-
Wenn Divisor größer ist als Dividende, zu stoppen.
-
Während Divisor-Register kleiner als Dividenden-Register, Verschiebung nach links.
-
Shift-Teiler registrieren rechts um 1.
-
Subtract Divisor von Dividenden-Registern registrieren und das Bit auf 1 in dem Ergebnisregister am Bit ändern, entspricht die Gesamtzahl der Schichten auf das Divisor-Register durchgeführt.
-
Von vorn anfangen in Schritt 1 mit Divisor-Register in ursprünglichen Zustand zurück.
Natürlich werden Sie in einer Check setzen müssen von 0 zum Teil, aber es sollte funktionieren.
Diese Algorithmen sind natürlich nur für ganze Zahlen sind.
Andere Tipps
Meine Lieblings Referenz für Dinge wie diese, in Buchform:
http://www.hackersdelight.org/
Sie können auch nicht falsch mit TAOCP gehen: http: // www-cs-faculty.stanford.edu/~uno/taocp.html
Hier ist ein Divisionsalgorithmus: http: // www. prasannatech.net/2009/01/division-without-division-operator_24.html
Ich gehe davon reden wir über ints?
Wenn es keine Hardware-Unterstützung, müssen Sie Ihre eigene Division durch Null Ausnahme implementieren.
(Ich habe nicht viel Glück haben schnell eine Multiplikation Algorithmus zu finden, aber ich werde schauen halten, wenn jemand anderes einen nicht findet).
Eine einfache und recht performant Multiplikationsalgorithmus für ganze Zahlen ist Russische ländliche Multiplikation .
Für rationals, könnten Sie versuchen, eine binäre Zitat Notation , für die ist Teilung leichter als üblich.
Es stellt sich heraus, dass ich noch einige alte 68000 Assembler-Code für lange Multiplikation und Division lange haben. 68000 Code ist ziemlich sauber und einfach, sollte so einfach sein, für Ihren Chip zu übersetzen.
Die 68000 hatte Multiplikation und Division Anweisungen IIRC -. Ich denke, diese als Lernübung geschrieben wurden
Beschlossen, nur hier, um den Code zu setzen. Hinzugefügt Kommentare und in dem Prozess, ein Problem behoben.
;
; Purpose : division of longword by longword to give longword
; : all values signed.
; Requires : d0.L == Value to divide
; : d1.L == Value to divide by
; Changes : d0.L == Remainder
; : d2.L == Result
; : corrupts d1, d3, d4
;
section text
ldiv: move #0,d3 ; Convert d0 -ve to +ve - d3 records original sign
tst.l d0
bpl.s lib5a
neg.l d0
not d3
lib5a: tst.l d1 ; Convert d1 -ve to +ve - d3 records result sign
bpl.s lib5b
neg.l d1
not d3
lib5b: tst.l d1 ; Detect division by zero (not really handled well)
bne.s lib3a
rts
lib3a: moveq.l #0,d2 ; Init working result d2
moveq.l #1,d4 ; Init d4
lib3b: cmp.l d0,d1 ; while d0 < d1 {
bhi.s lib3c
asl.l #1,d1 ; double d1 and d4
asl.l #1,d4
bra.s lib3b ; }
lib3c: asr.l #1,d1 ; halve d1 and d4
asr.l #1,d4
bcs.s lib3d ; stop when d4 reaches zero
cmp.l d0,d1 ; do subtraction if appropriate
bhi.s lib3c
or.l d4,d2 ; update result
sub.l d1,d0
bne.s lib3c
lib3d: ; fix the result and remainder signs
; and.l #$7fffffff,d2 ; don't know why this is here
tst d3
beq.s lib3e
neg.l d2
neg.l d0
lib3e: rts
;
; Purpose : Multiply long by long to give long
; Requires : D0.L == Input 1
; : D1.L == Input 2
; Changes : D2.L == Result
; : D3.L is corrupted
;
lmul: move #0,d3 ; d0 -ve to +ve, original sign in d3
tst.l d0
bpl.s lib4c
neg.l d0
not d3
lib4c: tst.l d1 ; d1 -ve to +ve, result sign in d3
bpl.s lib4d
neg.l d1
not d3
lib4d: moveq.l #0,d2 ; init d2 as working result
lib4a: asr.l #1,d0 ; shift d0 right
bcs.s lib4b ; if a bit fell off, update result
asl.l #1,d1 ; either way, shift left d1
tst.l d0
bne.s lib4a ; if d0 non-zero, continue
tst.l d3 ; basically done - apply sign?
beq.s lib4e ; was broken! now fixed
neg.l d2
lib4e: rts
lib4b: add.l d1,d2 ; main loop body - update result
asl.l #1,d1
bra.s lib4a
übrigens - ich habe nie herausfinden, ob es notwendig wäre, alles zu positiv zu Beginn zu konvertieren. Wenn Sie vorsichtig mit dem Schichtbetrieb, dass vermeidbarer Kopf sein kann.
zu multiplizieren, addieren Teilprodukte von dem Multiplikanden an einen Akkumulator verschoben iff das entsprechende Bit in den Multiplizierer Satz ist. Shift Multiplikand und Multiplikator am Ende der Schleife, Test Multiplikator & 1 zu sehen, ob zusätzlich getan werden sollte.
Die Microchip PICmicro 16Fxxx Serie Chips haben keine multiplizieren oder dividieren Anweisung. einige der weichen Vielleicht vermehren und weiche divide Routinen für sie kann auf Ihre MCU portiert werden.
PIC-Mikrocontroller Grund Math Multiplikation Methoden
PIC-Mikrocontroller Grund Math Abteilung Methoden
Überprüfen Sie auch heraus "Newton-Verfahren" für die Teilung . Ich denke, dass Verfahren, die kleinste Größe der ausführbaren Datei eines Divisionsalgorithmus gibt, gebe ich je gesehen habe, obwohl die Erklärung macht es klingen komplizierter, als es wirklich ist. Ich höre, dass einige frühe Cray Supercomputer Newton-Verfahren für die Division verwendet.