简体   繁体   中英

Why am I getting overflow? (NASM Assembler)

I have to make a program that calculates the volume of a cone which is 22/21*(r^2)*h for purposes of this program.

So this code I developed works for me for any variables that don't cause the EDX register to become populated after multiplying the variables together. I can't shift registers or "OR" them together, nor can I use jumps or cmp statements. I also must use 8 bit registers for the height and width variables, 16 bit for the radius^2 and radius^2*height calculations, and then finish it off with 32 bit for the final division calculation. Take a look. I don't know why it is overflowing into EDX and I don't know how to correct it...

.data

radius          WORD ?                                      ;var for radius
height          WORD ?                                      ;var for height
numerator       WORD 22                                     ;Making a variable for numerator
denominator     DWORD 21                                    ;Making a variable for denominator
volume          DWORD ?                                     ;Making a variable to store volume main
decimal         DWORD ?                                     ;Making a variable to store volume remainder
prompt BYTE "Enter the radius: ",0                          ;val for radius prompt
promp2 BYTE "Enter the height: ",0                          ;val for height prompt
result BYTE "The volume of the cone is: ", 0                ;val for printing volume
decim  BYTE ".", 0                                          ;val for decimal place

                                                                ;volume of cone is 1/3(pi(r^2)h) or 22/21(r^2)h

.code

main PROC
    mov edx,OFFSET promp2                                       ;move prompt into edx for printing
    call WriteString                                            ;ask user for height

    mov eax,0
    mov edx,0
    mov ecx,0
    mov ebx,0                                                   ;move zero into all main registers

    call ReadDec                                                ;reading the height
    mov bl,al                                                   ;move height into storage

    mov edx,OFFSET prompt                                       ;move promp2 into edx for printing
    mov eax,0                                                   ;re-zero eax
    call WriteString                                            ;ask user for radius
    call ReadDec

    mul al                                                      ;obtain r^2
    mul bl                                                      ;multiply r^2 by height
    mov edx,0                                                   ;zero out edx
    mov dx,numerator                                            ;move numerator into dx
    mul dx                                                      ;multiply r^2*h by 22

    mov ebx,denominator                                         ;move 21 into ebx to divide
    div ebx                                                     ;divide by 21 to get total volume
    mov volume,eax                                              ;move volume into volume variable
    mov decimal,edx                                             ;move decimal remainder into decimal variable

    mov edx,OFFSET result                                       ;prepare string result for printing
    call WriteString                                            ;print result string
    mov eax,volume                                              ;move volume into eax to print     
    call WriteDec                                               ;print volume
    mov edx,OFFSET decim                                        ;move dec into print register
    call WriteString                                            ;print decimal
    mov eax,decimal                                             ;move decimal remainder into eax to print
    call WriteDec                                               ;print decimal value
    call CRLF                                                   ;carriage return and new line
    call WaitMsg                                                ;pause output

    exit
main ENDP

Maybe I could do different registers for the intermediate arithmetic, but I have no idea how to accomplish that given the current 8-8-16-16-32 requirements. If anyone could help me with a working solution and explain why it works, maybe step through it so I can understand why mine doesn't work for larger integers (most over 20 don't work) that would be amazing. Thank you ahead of time for any help you can give me!

Let's walk through the whole calculation:

mul   al               ;obtain r^2

This mul al leaves a result in the AX register. So you must use a word multiply in the next line or else you loose a part of the value of r^2 .

mov   bh, 0
mul   bx               ;multiply r^2 by height

Now the result is in DX:AX . To multiply it by 22 you can move it to the 32 bit register EAX by means of the stack.

push  dx
push  ax
pop   eax
movzx edx, numerator   ;Why is this defined a word?
mul   edx

This time the result is in EDX:EAX , ready for the final division.

div   denominator

Finally move quotient in EAX and remainder in EDX to their respective variables.

mov   volume, eax      ;move volume into volume variable
mov   decimal, edx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM