Search code examples
assemblytasm

Assembly TASM: Multiply 4 digit numbers by 4 digit numbers


I am trying to create a calculator program using Assembly Language but it is required for us to show 4 digit number operations.

In this code, I can add, subtract and divide numbers with 4 digits each, but when multiplying 4 digit by 4 digit numbers, the answer is different and wrong

Example: 9999x9999= 37601 (which is wrong and the answer should be 99980001)

Here is the part of the code for Multiplication:

mult: 
pop ax
mul bx      
push ax     
lea dx,Mulseu   
mov ah,09h
int 21h 
pop ax
mov cx,0
mov dx,0
mov bx,10d
jmp wrong

Here is the FULL code:

.model small
.stack 100h

.data
msg1    db 13, 10, 13, 10,"MENU "
        db 10, 13,"1. Add   "
        db 10, 13,"2. Subtract "
        db 10, 13,"3. Multiply "
        db 10, 13,"4. Divide "
        db 10, 13,"5. Exit "
        db 13,10,13,10, "Enter 1st Number : $"
msg2 db 13,10, "Enter 2nd Number : $"
msgEr db 13,10, "Error $"
choiceseu db 13,10, "Enter choice: $ "
sumseu db 13,10,13,10, "***Sum is : $"
Diffseu db 13,10,13,10, "***Difference is : $"
Divseu db 13,10,13,10, "***Quotient is : $"
Mulseu db 13,10,13,10, "***Product is : $"
temp     db ?


.code

start:
mov ax, @data
mov ds, ax

lea dx, msg1
mov ah, 09h
int 21h
mov bx, 0

ph1:
mov ah, 01h
int 21h
cmp al,0dh      
je input1
mov ah,0        
sub al,30h      
push ax         
mov ax,10d      
mul bx          
pop bx          
add bx,ax       
jmp ph1      




input1:
push bx
lea dx,msg2
mov ah,09h
int 21h

mov bx,0


ph2:
mov ah,01h
int 21h
cmp al,0dh
je choice
mov ah,0
sub al,30h
push ax
mov ax,10d
mul bx
pop bx
add bx,ax 
jmp ph2


choice:
lea dx, choiceseu
mov ah, 09h
int 21h

mov ah, 01h
int 21h


cmp al,'4'
je divd

cmp al,'1'  
je addz

cmp al,'2'
je subt

cmp al,'3'
je mult

cmp al,'5'
mov ah, 4ch
int 21h

error:
lea dx,msgEr
mov ah,09h
int 21h 
jmp start


divd: 
pop ax
mov dx, 0
div bx
push ax
lea dx,Divseu
mov ah,09h
int 21h 
pop ax
mov cx,0
mov dx,0
mov bx,10d
jmp wrong

addz:     
pop ax
add ax,bx   
push ax
lea dx,sumseu   
mov ah,09h
int 21h 
pop ax
mov cx,0
mov dx,0
mov bx,10d
jmp wrong   

mult: 
pop ax
mul bx      
push ax     
lea dx,Mulseu   
mov ah,09h
int 21h 
pop ax
mov cx,0
mov dx,0
mov bx,10d
jmp wrong


subt: 
pop ax
sub ax,bx 
push ax
lea dx,Diffseu
mov ah,09h
int 21h 
pop ax
mov cx,0
mov dx,0
mov bx,10d

wrong:
mov dx, 0
div bx
push dx
mov dx,0
inc cx
or ax,ax 
jne wrong 

ans:        
pop dx
add dl,30h
mov ah,02h
int 21h
loop ans

jmp start



end start

Solution

  • mult: 
    pop ax
    mul bx      
    push ax     
    lea dx,Mulseu   
    mov ah,09h
    int 21h 
    pop ax
    mov cx,0
    mov dx,0
    mov bx,10d
    jmp wrong
    

    Since you want to display the full 32-bit result (in DX:AX) from the multiplication, you can't let the DX register go to waste! You need to preserve it just like you did with AX.
    Because your current conversion/displaying routine (Why o why is this named wrong ?) only knows about 16-bit numbers, you'll need another routine that I'll present below. This routine comes from another answer that I wrote some time ago. You should definitely read it. It explains in great detail how these things work and so I shall not repeat that explanation here.

    mult: 
        pop     ax
        mul     bx      
        push    ax
        push    dx    
        lea     dx, Mulseu   
        mov     ah, 09h
        int     21h 
        pop     dx
        pop     ax
        jmp     DisplayNumber32
    
        ...
    
    DisplayNumber32:
        mov     bx,10          ;CONST
        push    bx             ;Sentinel
    .a: mov     cx,ax          ;Temporarily store LowDividend in CX
        mov     ax,dx          ;First divide the HighDividend
        xor     dx,dx          ;Setup for division DX:AX / BX
        div     bx             ; -> AX is HighQuotient, Remainder is re-used
        xchg    ax,cx          ;Temporarily move it to CX restoring LowDividend
        div     bx             ; -> AX is LowQuotient, Remainder DX=[0,9]
        push    dx             ;(1) Save remainder for now
        mov     dx,cx          ;Build true 32-bit quotient in DX:AX
        or      cx,ax          ;Is the true 32-bit quotient zero?
        jnz     .a             ;No, use as next dividend
        pop     dx             ;(1a) First pop (Is digit for sure)
    .b: add     dl,"0"         ;Turn into character [0,9] -> ["0","9"]
        mov     ah,02h         ;DOS.DisplayCharacter
        int     21h            ; -> AL
        pop     dx             ;(1b) All remaining pops
        cmp     dx,bx          ;Was it the sentinel?
        jb      .b             ;Not yet
    

    For all the remaining operations (addz, subt, divd) you can also use this new DisplayNumber32 routine. Just make sure to zero the DX register beforehand.

    subt: 
        pop     ax
        sub     ax, bx 
        push    ax
        lea     dx, Diffseu
        mov     ah, 09h
        int     21h 
        pop     ax
        xor     dx, dx              ;Add this for the 32-bit version!
        jmp     DisplayNumber32