Programm zur Multiplikaton ohne den Befehl MUL



  • Hallo, Ich möchte ein Programm zur Multiplikation zweier Zahlen ohne den Befehl MUL zu benutzen. Könnte mir bitte jemand hier helfen um den Code zu schreiben?

    Thanx



  • Benutze add in einer Schleife wäre mein Ansatz,
    aber ich würd trotzdem mul nehmen 🙂



  • nimmste den einen wert als schleifenzähler und den anderen addierste immer wieder auf



  • performanter wird's, wenn man sich die grundlagen der binärzahlen zunutze macht:

    int mul(int a, int b)
    {
    	int res=0;
    	for (int i=0;i<numBits;i++)
    	{
    		if (a & 1) res+=b;
    		a>>=1;
    		b<<=1;
    	}
    	return res;
    }
    

    wobei numBits=32 bzw entsprechend der operandengroesse zu wählen ist.
    für vorzeichenbehaftete zahlen benötigt man noch entsprechende überprüfungen.



  • hellihjb schrieb:

    wobei numBits=32 bzw entsprechend der operandengroesse zu wählen ist.

    oder du ändert in

    for (int i=0;a!=0;i++)
    


  • volkard schrieb:

    hellihjb schrieb:

    wobei numBits=32 bzw entsprechend der operandengroesse zu wählen ist.

    oder du ändert in

    for (int i=0;a!=0;i++)
    

    oder

    while(a)
    

    ist einfacher und fixer.



  • Hey Volkard und Rapso, 🙂

    Ich meine sondern in Assembler und nicht C++ 🙂 😞



  • das kriegst du bestimmt selber hin, der algorithmus ist ja wirklich leicht und laesst sich 1:1 uebertragen...



  • hellihjb schrieb:

    das kriegst du bestimmt selber hin, der algorithmus ist ja wirklich leicht und laesst sich 1:1 uebertragen...

    Hi ehrlich gesagt, bin ich noch Anfänger, ich versuche das zu schreiben und kompilieren aber geht nicht. Kannst du mal den code in asm erklären?





  • dydy schrieb:

    hellihjb schrieb:

    das kriegst du bestimmt selber hin, der algorithmus ist ja wirklich leicht und laesst sich 1:1 uebertragen...

    Hi ehrlich gesagt, bin ich noch Anfänger, ich versuche das zu schreiben und kompilieren aber geht nicht. Kannst du mal den code in asm erklären?

    klar können wir das, zeig deinen code und wir klären gerne wo das problem liegt.



  • ich mach mir mal die muehe...

    // register eax und ebx enthalten zu multiplizierende operanden a & b
          mov  ecx,0     // ergebnis initial = 0
    mulloop:
          test eax,1     // pruefe unterstes bit von operand a
          jz   skip      // wenn's nicht gesetzt ist, folgende addition ueberspringen
          add  ecx,ebx   // addiere operand b zum ergebnis
    skip:
          shl  ebx,1     // alle bits von operand b um ein bit nach oben verschieben
          shr  eax,1     // alle bits von operand a um ein bit nach unten verschieben
          jnz  mulloop   // solang operand a ungleich 0...
    done:
          // ergebnis in ecx
    

    je nach verwendetem compiler sind die sprungmarken mit beliebig vielen @ zu versehen.
    was der algorithmus macht ist, fuer jedes gesetzte bit "n" von operand a zum ergebnis b*(2^n) zu addieren, also das gleiche wie eine schriftliche multiplikation nur eben im dual- anstatt im dezimalsystem.
    anstatt jeweils das n-te bit von operand a zu pruefen, wird immer das unterste bit geprueft und der komplette operand um eine bitstelle verschoben (shr eax,1), wobei automatisch das zero-flag gesetzt wird, falls operand a nur noch nullen enthaellt, und dadurch die schleife (mulloop) unterbrochen.
    operand b wird entsprechend jeweils um eine stelle nach oben verschoben, sodass ebx bei jedem durchlauf "n" schon b*(2^n) enthaelt und bei einem gesetzten bit0 in eax einfach auf das ergebnis addiert werden muss.
    der algorithmus funktioniert auch fuer negative zahlen, weil das vorzeichen im obersten bit erhalten bleibt. nachteil in dem fall ist, dass die loop fuer einen negativen operand a immer 32 durchlaeufe macht, da ja dessen oberstes bit gesetzt ist. fuer kleine zahlen waere es also performanter das vorzeichen im vorfeld zu ueberpruefen, den algorithmus mit positivem a auszufuehren und das vorzeichen am ende entsprechend anzupassen.
    da die fortfuehrung der schleife erst am ende geprueft wird, wird sie auch einmal fuer den fall a=0 durchlaufen, was quatsch ist, aber den code kuerzer macht - wer performant mit 0 multiplizieren will, findet dafuer auch sicherlich geistreichere moeglichkeiten...
    darueber hinaus koennen in operand a beliebige bitmuster stehen, sodass die sprungvorhersage zum ueberspringen der addition relativ wahrscheinlich versagen wird. performanter waere daher die addition immer auszufuehren und aus dem zustand des gesetzten bit0 eine entsprechende bitmaske zu erzeugen, die den zu addierenden operand b entweder auf 0 setzt (bit0=0) oder unveraendert laesst (bit0=1), zb so:

    mov  edx,eax // operand a in temporaeres register laden
    and  edx,1   // nur bit0 behalten
    dec  edx     // 1 subtrahieren (bit0=0: 0xffffffff  bit0=1: 0)
    not  edx     // bits negieren (bit0=0: 0  bit0=1: 0xffffffff)
    and  edx,ebx // und-verknuepfung mit operand b (bit0=0: 0  bit0=1: b)
    add  ecx,edx // zum ergebnis addieren
    

    damit sollte das thema eigentlich inhaltlich erschoepft sein...


Anmelden zum Antworten