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 DX

    CX mit AX
    DI mit DX

    multipliziert 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:
    

Anmelden zum Antworten