MASM - 如何显示负整数的最小/最大、总和和平均值的正确值

问题描述 投票:0回答:1

我在尝试显示用户输入的负整数的最小/最大、总和和平均值的正确值时遇到问题。当我运行代码并输入两个负值(-10 和 -30)时,结果如下(用户输入以粗体显示):

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

您是否发现数字的总和、最小值、最大值和平均值都不正确?这就是我正在努力解决的问题。预期输出应该是:

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

这是下面的代码。我可能还需要将 numAverage 数据变量更改为浮点数,但我还没有测试它:

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
assembly x86 number-formatting masm irvine32
1个回答
0
投票

怎么了?

比较您的期望:

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

用你得到的:

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

很明显您正在将这些带符号的结果作为无符号数字输出。
仔细观察最小有效数字的值 4294967196 还可以发现,程序中的某个地方一定存在错误(因为 -30 应该显示为 4294967266)。

解决以上问题

  • 您使用了错误的 Irvine32 函数。使用

    WriteDec
    来输出 signed 32 位整数,而不是用于输出 unsigned
     32 位整数。
    您已将

    numMin
  • 初始化为
  • UPPER_BOUND1

    但这不是最大可能值(尽管您在评论中说明了这一点)。真正最大的可能值是 UPPER_BOUND2 等式中的 -1,因此请使用以下命令更正它: mov numMax, LOWER_BOUND1 ;初始化为可能的最小值-200 mov numMin, UPPER_BOUND2 ;初始化为最大可能值-1

    您过于频繁地使用基于内存的变量!
一旦变量被加载到寄存器中,它就可以从该寄存器中保持可用(当然,直到您对寄存器进行更改)。在下面的代码片段中,我标记了您可以而且肯定应该用 EAX 替换
inputNumber

的行:

WriteInt 以复制粘贴的方式(你不会相信你会删掉多少字节):

    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

© www.soinside.com 2019 - 2024. All rights reserved.