user23372697
user23372697

Reputation: 11

How to display correct values for Min, Max, Sum, and Average of negative integers

I'm having trouble trying to display the correct values for Min, Max, Sum, and Average of user-inputted negative integers. When I run my code and enter two negative values (-10 and -30), here are the results (user inputs in bold):

Welcome to the Integer Accumulator by John
We will be accumulating user-input negative integers between the specified bounds, then displaying statistics of the
input values including minimum, maximum, and average values values, total sum, and total number of valid inputs.
What is your name? **John**
Hello there, John

Please enter numbers in [-200, -100] or [-50, -1].
Enter a non-negative number when you are finished, and input stats will be shown.
Enter number: **-10**
Enter number: **-30**
Enter number: 0
You entered 2 valid numbers.
The sum of your valid numbers is 4294967256
The maximum valid number is 4294967286
The minimum valid number is 4294967196
The rounded average is 4294967276
We have to stop meeting like this. Farewell, John

Do you see how the sum, min, max, and average of the numbers are all incorrect? That's what I'm trying to fix. The expected output should be:

The sum of your valid numbers is -40
The maximum valid number is -10
The minimum valid number is -30
The rounded average is -20

Here's the code below. I also may need to change the numAverage data variable to be a float, but I have not tested it yet:

INCLUDE Irvine32.inc

.data
titleMsg        BYTE    "Welcome to the Integer Accumulator by ", 0
myName          BYTE    "John", 0
progMsg         BYTE    "We will be accumulating user-input negative integers between the specified bounds, then displaying statistics of the ", 0
progMsg2        BYTE    "input values including minimum, maximum, and average values values, total sum, and total number of valid inputs.", 0
namePrompt      BYTE    "What is your name? ", 0
greetMsg        BYTE    "Hello there, ", 0
instruction     BYTE    "Please enter numbers in [-200, -100] or [-50, -1].", 0
instruction2    BYTE    "Enter a non-negative number when you are finished, and input stats will be shown.", 0
invalidMsg      BYTE    "This is not a number we're looking for (Invalid Input)!", 0
inputPrompt     BYTE    "Enter number: ", 0
statsMsg        BYTE    "You entered ", 0
validMsg        BYTE    " valid numbers.", 0
maxMsg          BYTE    "The maximum valid number is ", 0
minMsg          BYTE    "The minimum valid number is ", 0
sumMsg          BYTE    "The sum of your valid numbers is ", 0
avgMsg          BYTE    "The rounded average is ", 0
farewellMsg     BYTE    "We have to stop meeting like this. Farewell, ", 0
specialMsg      BYTE    "Congratulations, you found an Easter Egg!", 0
SUM_LIMIT       EQU     1000    ; Limit for the sum of numbers entered

; Constants for value limits
LOWER_BOUND1    EQU     -200
UPPER_BOUND1    EQU     -100
LOWER_BOUND2    EQU     -50
UPPER_BOUND2    EQU     -1

; Variables
userName        BYTE    50 DUP (?)
inputNumber     SDWORD  ?
validCount      DWORD   ?
numSum          SDWORD  ?
numMax          SDWORD  ?
numMin          SDWORD  ?
numAverage      SDWORD  ?
signFlag        BYTE    ?

.code
main PROC
    ; Display program title and programmer's name
    mov  edx, OFFSET titleMsg
    call WriteString
    mov edx, OFFSET myName
    call WriteString
    call Crlf

    ; Display program description
    mov  edx, OFFSET progMsg
    call WriteString
    call Crlf
    mov  edx, OFFSET progMsg2
    call WriteString
    call Crlf

    ; Get the user's name and greet the user
    mov  edx, OFFSET namePrompt
    call WriteString
    mov  edx, OFFSET userName
    mov  ecx, SIZEOF myName
    call ReadString
    mov edx, OFFSET greetMsg
    call WriteString
    mov edx, OFFSET userName
    call WriteString
    call Crlf
    call Crlf
    
    ; Display instructions
    mov  edx, OFFSET instruction
    call WriteString
    call CrLf
    mov  edx, OFFSET instruction2
    call WriteString
    call CrLf

    ; Initialize variables
    mov  numSum, 0
    mov  validCount, 0
    mov  numMax, LOWER_BOUND1       ; Initialize to the smallest possible value
    mov  numMin, UPPER_BOUND1       ; Initialize to the largest possible value

    ; User input loop

inputLoop:
    ; Prompt user to enter a number
    mov  edx, OFFSET inputPrompt
    call WriteString
    call ReadInt
    mov  inputNumber, eax

    ; Check if the number is non-negative
    test eax, eax
    jns  checkSpecialMessage

    ; Check if the number is within the specified ranges
    cmp  inputNumber, LOWER_BOUND1
    jl   invalidInput
    cmp  inputNumber, UPPER_BOUND1
    jg   checkSecondRange
    jmp  validInput

checkSecondRange:
    cmp  inputNumber, LOWER_BOUND2
    jl   invalidInput
    cmp  inputNumber, UPPER_BOUND2
    jg   invalidInput
    jmp  validInput

invalidInput:
    ; Notify user of invalid input
    mov  edx, OFFSET invalidMsg
    call WriteString
    call CrLf
    jmp  inputLoop

validInput:
    ; Update count and sum of valid numbers
    inc  validCount
    mov  eax, inputNumber ; Move inputNumber into eax register
    add  numSum, eax      ; Add eax (inputNumber) to numSum

    ; Update max and min valid numbers
    mov  eax, numMax      ; Move numMax into eax register
    cmp  inputNumber, eax ; Compare inputNumber with eax (numMax)
    jle  notMax
    mov  eax, inputNumber ; Move inputNumber into eax register
    mov  numMax, eax      ; Move eax (inputNumber) to numMax
notMax:
    mov  eax, numMin      ; Move numMin into eax register
    cmp  inputNumber, eax ; Compare inputNumber with eax (numMin)
    jge  notMin
    mov  eax, inputNumber ; Move inputNumber into eax register
    mov  numMin, eax      ; Move eax (inputNumber) to numMin
notMin:
    jmp  inputLoop

checkSpecialMessage:
    ; Check if any valid inputs were received
    cmp validCount, 0
    je displaySpecialMessage        ; If no valid inputs were received, display special message
    jmp displayStats                ; If valid inputs were received, display statistics

displaySpecialMessage:
    ; Display special message
    mov  edx, OFFSET specialMsg
    call WriteString
    call CrLf

    ; Display farewell message with the user's name
    mov  edx, OFFSET farewellMsg
    call WriteString
    mov  edx, OFFSET userName
    call WriteString

displayStats:
    ; Calculate the rounded average
    mov  eax, numSum
    cdq
    idiv validCount
    mov  numAverage, eax

    ; Display statistics
    mov  edx, OFFSET statsMsg
    call WriteString
    mov  eax, validCount
    call WriteDec
    mov  edx, OFFSET validMsg
    call WriteString
    call CrLf
    mov  edx, OFFSET sumMsg
    call WriteString
    mov  eax, numSum
    call WriteDec
    call CrLf
    mov  edx, OFFSET maxMsg
    call WriteString
    mov  eax, numMax
    call WriteDec
    call CrLf
    mov  edx, OFFSET minMsg
    call WriteString
    mov  eax, numMin
    call WriteDec
    call CrLf
    mov  edx, OFFSET avgMsg
    call WriteString
    mov  eax, numAverage
    call WriteDec
    call CrLf

    ; Display farewell message with the user's name
    mov  edx, OFFSET farewellMsg
   call WriteString
    mov  edx, OFFSET userName
    call WriteString
    exit

main ENDP

END main

Upvotes: 1

Views: 50

Answers (1)

Sep Roland
Sep Roland

Reputation: 39166

What is the matter?

Comparing what you were expecting:

The sum of your valid numbers is -40
The maximum valid number is -10
The minimum valid number is -30
The rounded average is -20

with what you got:

The sum of your valid numbers is 4294967256
The maximum valid number is 4294967286
The minimum valid number is 4294967196
The rounded average is 4294967276

it is immediately clear that you are outputting these signed results as unsigned numbers.
A closer look at the value 4294967196 for the minimum valid number also reveals that there has to be an error somewhere in the program (because -30 ought to have displayed as 4294967266).

Solving the above issues

  • You are using the wrong Irvine32 function. Instead of WriteDec that is meant to output unsigned 32-bit integers, use WriteInt to output signed 32-bit integers.

  • You have initialized numMin to UPPER_BOUND1 but that is not the largest possible value (although you state it in your comment). The truly largest possible value is the -1 from the UPPER_BOUND2 equate, so correct it with:

      mov  numMax, LOWER_BOUND1       ; Initialize to the smallest possible value -200
      mov  numMin, UPPER_BOUND2       ; Initialize to the largest possible value -1
    

You are using the memory-based variables too often!

Once a variable has been loaded in a register, it remains available from that register (until you make changes to the register of course). In the following snippet I have marked the lines where you can and most certainly should replace inputNumber by EAX:

    mov  inputNumber, eax

    test eax, eax
    jns  checkSpecialMessage

    cmp  inputNumber, LOWER_BOUND1            cmp eax, LOWER_BOUND1
    jl   invalidInput
    cmp  inputNumber, UPPER_BOUND1            cmp eax, UPPER_BOUND1
    jg   checkSecondRange
    jmp  validInput

checkSecondRange:
    cmp  inputNumber, LOWER_BOUND2            cmp eax, LOWER_BOUND2
    jl   invalidInput
    cmp  inputNumber, UPPER_BOUND2            cmp eax, UPPER_BOUND2
    jg   invalidInput                  \ jng validInput
    jmp  validInput                    / ; else fall-through
invalidInput:
    mov  edx, OFFSET invalidMsg
    call WriteString
    call CrLf
    jmp  inputLoop

validInput:
    inc  validCount
    mov  eax, inputNumber                     Remove this, EAX still has inputNumber
    add  numSum, eax

    mov  eax, numMax                          Remove this, No need to load/clobber EAX
    cmp  inputNumber, eax                     Then write this as: cmp eax, numMax
    jle  notMax
    mov  eax, inputNumber                     Remove this, EAX still has inputNumber
    mov  numMax, eax
notMax:
    mov  eax, numMin                          Remove this, No need to load/clobber EAX
    cmp  inputNumber, eax                     Then write this as: cmp eax, numMin
    jge  notMin
    mov  eax, inputNumber                     Remove this, EAX still has inputNumber
    mov  numMin, eax
notMin:
    jmp  inputLoop

In a copy-paste fashion (and you won't believe how many bytes you will have shaved off):

    mov  inputNumber, eax

    test eax, eax
    jns  checkSpecialMessage

    cmp  eax, LOWER_BOUND1
    jl   invalidInput
    cmp  eax, UPPER_BOUND1
    jg   checkSecondRange
    jmp  validInput

checkSecondRange:
    cmp  eax, LOWER_BOUND2
    jl   invalidInput
    cmp  eax, UPPER_BOUND2
    jng  validInput
invalidInput:
    mov  edx, OFFSET invalidMsg
    call WriteString
    call CrLf
    jmp  inputLoop

validInput:
    inc  validCount
    add  numSum, eax

    cmp  eax, numMax
    jle  notMax
    mov  numMax, eax
notMax:
    cmp  eax, numMin
    jge  notMin
    mov  numMin, eax
notMin:
    jmp  inputLoop

Upvotes: 0

Related Questions