Vorzeichenbehaftet richtig multiplizieren
-
Hallo!
Ich habe gegeben:
-Adresse einer 64-Bit Int - Variable in EBX (vorzeichenbehaftet)
-32-Bit Int in DX:AX (vorzeichenbehaftet)
-32-Bit Int in DI:CX (vorzeichenbehaftet)Gefordert: Multiplikation der gegebenen vorzeichenbehafteten Zahlen. Ergebnis steht in in der durch EBX adressierten Speicherstelle.
So, nun habe ich erstmal die Sache für vorzeichelose Zahlen gelöst. Und zwar habe ich
CX mit DX
DI mit DXCX mit AX
DI mit DXmultipliziert und die Teilprodukte entsprechend mit allen möglichen Überträgen in die durch EBX adressierte Variable abgelegt. Hat geklappt. Nur wie ziehe ich die Sache für vorzeichenbehaftete Zahlen durch?
Meine Idee wäre gerade: Das höchste Bit der jeweiligen Zahl untersuchen und zu einem entsprechenden neuen Vorzeichen verrechnen; dieses dann abspeichern. Jedes höchste Bit auf Null setzten.
Dann mit den Zahlen vorzeichenlos rechnen und dem Ergebnis das abgespeicherte Vorzeichen hinzufügen.Ginge das?
-
gruml gruml schrieb:
Hallo!
Meine Idee wäre gerade: Das höchste Bit der jeweiligen Zahl untersuchen und zu einem entsprechenden neuen Vorzeichen verrechnen; dieses dann abspeichern. Jedes höchste Bit auf Null setzten.
Dann mit den Zahlen vorzeichenlos rechnen und dem Ergebnis das abgespeicherte Vorzeichen hinzufügen.Ginge das?
Nein -> folgendes Beispiel:
-1 = 0xffffffff (32bit)
wenn du das sign-bit auf null setzt bekommst du:
0x7fffffff == 2147483647.Umwandeln kannst du z.B. indem du die Zahl invertierst und anschließend inkrementierst (NOT(a) + 1). Dafür gibt es natürlich auch einen Befehle: 'neg'
aus deiner Frage entnehme ich das ein 32bit Prozessor vorliegt (ebx) -> das mach die Sache doch sehr einfach, da die einzige "Schwierigkeit" darin liegt DX:AX und DI:CX so um zu wandeln, das man imul (oder mul) verwenden kann:
;masm-syntax shl edx,16 and eax,0ffffh ; hi-word muss 0 sein or eax,edx shl edi,16 and ecx,0ffffh or ecx,edi imul ecx ;mul ecx mov DWORD ptr [ebx],eax mov DWORD ptr [ebx+4],edx
-
Ach Mist! Ich vergesse immer wieder, dass man im Binären das Zweierkomplement bilden muss...
Die Aufgabe ist mit 16Bit-Registern zu lösen. Ich habe die Adresse in EBX reingeschoben, weils auf einer 32Bit-Rechner es nun wohl nicht anders geht und ich mein Konstrukt auch ausprobieren wollte.
-
Na gut, dann würd ich einfach von einer Zahl, ist sie negativ, das Zweierkomplement bilden und vorzeichenlos multiplizieren. Und dann das entsprechende Vorzeichen einbringen bzw, ist das Vorzeichen -, Zweierkomplement vom Ergebnis bilden, ist das Vorzeichen +, das Ergebnis so lassen wie es ist.
Ginge das aber bequemer?
-
Ich habs jetzt geschrieben, es ist aber ein riesen Unding geworden. Wüßte jemand was besseres?
segment .text global mult %define Prod_Ptr [ebp+16] %define OP2 [ebp+12] %define OP1 [ebp+8] %define vorz [ebp-4] mult: enter 1,0 pusha mov ebx,Prod_Ptr mov ax,[ebp+8] mov dx,[ebp+10] mov cx,[ebp+12] mov di,[ebp+14] test_dx: test dx,0FFFFH jz test_ax test dx,8000H jz positiv_ax_dx jnz negativ_ax_dx test_ax: test ax,0FFFFH jz rechnung test ax,8000H jz positiv_ax_dx jnz negativ_ax_dx positiv_ax_dx: mov vorz,byte 0 jmp test_di negativ_ax_dx: mov vorz,byte 1 not dx not ax add ax,1 adc dx,0 test_di: test di,0FFFFH jz test_cx test di,8000H jz positiv_cx_di jnz negativ_cx_di test_cx: test cx,0FFFFH jz rechnung test cx,8000H jz positiv_cx_di positiv_cx_di: add vorz, byte 0 jmp rechnung negativ_cx_di: add vorz, byte 1 not di not cx add cx,1 adc di,0 rechnung: push ax push dx xchg ax,dx mul cx mov [ebx+2],ax mov [ebx+4],dx pop ax mul di mov [ebx+6],dx add [ebx+4],ax jnc high_word inc word[ebx+6] high_word: pop ax push ax mul cx mov [ebx],ax add [ebx+2],dx jnc weiter inc word [ebx+4] jnc weiter inc word [ebx+6] weiter: pop ax mul di add [ebx+2],ax jnc vorzeichen inc word [ebx+4] jnc vorzeichen inc word [ebx+6] vorzeichen: test vorz,byte 1H jz ende not dword [ebx] not dword [ebx+4] add [ebx],dword 1 adc [ebx+4],dword 0 ende: popa leave ret
-
hier mal mein Vorschalg (hab es nicht getestet!):
; dw1 und dw2 = dword's , 0 = low word, 1 = high word ; SQWORD = dw1[1]*dw2[1]*(2^32) + ( dw1[0]*dw2[1] + dw1[0]*dw2[1] )*(2^16) + dw1[0]*dw2[0] mov BYTE ptr [esp-4],0 ;flag-variable auf dem Stack test dx,08000h jz @skip_1 not dx neg ax sbb dx,-1 mov BYTE ptr [esp-4],1 ; @skip_1: test di,08000h jz @skip_2 not di neg cx sbb di,-1 xor BYTE ptr [esp-4],1 ; kleiner Trick ;) @skip_2: mov si,dx mov bp,ax mul cx ;dw1[0]*dw2[0] mov WORD ptr [ebx],ax ;lo-dword mov WORD ptr [ebx+2],dx ; mov ax,si mul di ;dw1[0]*dw2[0] mov WORD ptr [ebx+4],ax ;high-dword mov WORD ptr [ebx+6],dx ; mov ax,bp mul di ;dw1[0]*dw2[1] add WORD ptr [ebx+2],ax adc WORD ptr [ebx+4],dx adc WORD ptr [ebx+6],0 mov ax,si mul cx ;dw1[0]*dw2[1] add WORD ptr [ebx+2],ax adc WORD ptr [ebx+4],dx adc WORD ptr [ebx+6],0 test BYTE ptr [esp-4],1 jz @fin not WORD ptr [ebx] not WORD ptr [ebx+2] not WORD ptr [ebx+4] not WORD ptr [ebx+6] add WORD ptr [ebx],1 adc WORD ptr [ebx+2],0 adc WORD ptr [ebx+4],0 adc WORD ptr [ebx+6],0 @fin: