计算四舍五入为整数的浮点数的平均值 NASM

Calculating average of floats rounded to an integer NASM

基本上程序假设从用户输入浮点数,然后得到它们的总和,它们的平均值(从 0.0 到 100.0),上面的不算,下面的不算出色地。负数不仅不计入,还会退出loop/program。输出和,输出输入的有效数的个数,最后输出浮点数四舍五入取最近整数的平均值。我想我现在很接近,到目前为止我的计划如下。 拜托,我可以使用一些帮助在我的下面的代码中找到错误/(推理错误,如果存在的话)。 注意我正在使用 NASM.

更新:当它运行并输入简单的 1、2、3、4 时,它应该输出 3(四舍五入到最接近的整数)是平均值,但它输出 100,这意味着它是 运行整个循环或类似的事情都出了问题。

更新:我发现问题应该有更多的比较,应该有更多的 ffree st0 来释放 st0,这一直在产生问题。不管怎样,它工作了。

 ; Declare needed external functions
 ;
extern  printf          ; the C function, to be called
extern scanf            ; the C function, to be called

SECTION .data                                                                   ; Data section, initialized variables
three: dq 3.0
erroro: db "Did not work as intended...", 10, 0
zero: dq 0.0
half: dq 0.5
max_val: dq 100.0                                                           ; max value is 100
min_val: dq 0.0                                                             ; min value is 0
input: db "%lf", 0                                                          ; input format
intro: db "Program title is Average and programmer is Joe", 10, 0   ; introduction format
iname: db "Enter your full name", 10, 0                                     ; get name instructions from user format
gname: db "%s %s", 0                                                        ; get first and lats name
inst: db "Enter a number between 0.0 and 100.0, negative number to exit", 10, 0 ; instruction format
countout: db "The number of valid numbers entered: %d", 10, 0               ; counter output format
sumoutput: db "The sum is: %f", 10, 0                                       ; sum output format
avgoutput: db "The average is: %d", 10, 0                                   ; average output format
specialbye: db "You didn't enter any numbers, something wrong %s %s?", 10, 0    ; special goodbye format (if user did not input any valid numbers)
bye: db "Thanks for using this program, %s %s", 10, 0                           ; goodbye output format

SECTION .bss                                                                    ; BSS, uninitialized variables
x: resq 1                                                                   ; number entered by user, set to 0
sum: resq 1                                                                 ; sum variable is set to 0
avgc: resq 1                                                                ; average used to compare (not what is outputted)
avg: resd 101                                                               ; an array that is used for lookup value of average (it is how it outputs an integer)
count: resd 1                                                               ; counter set to 0
avga: resq 201                                                              ; an array of values from .5 to 100 (by increments of .5) used for comparing avg
fn: resw 10                                                                 ; first name set to 0, with a size of 10 words
ln: resw 10                                                                 ; last name set to 0, with a size of 10 words

SECTION .text               ; Code section.

global main             ; the standard gcc entry point

main:                   ; the program label for the entry point
    push    ebp         ; set up stack frame
    mov     ebp,esp

    mov eax, 0
    mov ebx, 0
    mov ecx, 101
.setavg:                            ;average array set up (used to output)
    mov [avg+ebx], eax
    push eax
    mov eax, ebx
    add eax, 4
    mov ebx, eax
    pop eax
    add eax, 1

    loop .setavg

    finit
    ; get the first one taken care of...
    fld qword [zero]
    fstp qword [avga+0]
    mov ebx, 0
    mov ecx, 200
.setavga:                           ; average array set up to compare average values and then round to nearest integer (sort of..., actually it uses the average array to set which integer to "round to")
    fld qword [avga+ebx]
    fld qword [half]
    fadd
    mov eax, ebx
    add eax, 8
    mov ebx, eax
    fstp qword [avga+ebx]

    loop .setavga

    jmp .start                      ; skip to .start label, used for testing purposes to reduce user input during testing
    ; output introduction
    push dword intro
    call printf
    add esp, 4
    ; output asking for name
    push dword iname
    call printf
    add esp, 4
    ; get first and last name
    push dword ln
    push dword fn
    push dword gname
    call scanf
    add esp, 12

; start loop
.start:
    ; output number input instructions to user
    push dword inst
    call printf
    add esp, 4

    ;get number
    push dword x
    push dword input
    call scanf
    add esp, 8

    ;compare x and minimum value
    ;mov eax, [x]                                                           ; put x in eax          
    ;cmp eax, min_val                                                       ; compare x and minimum value
    ;jl .post_while                                                         ; if x is less than minimum value (which means it is a negative), jump to post while
    ; compare value to minimum value, if minimum is greater than user input, jump to post_while
    fld qword [x]
    fld qword [min_val]
    fcomip st0, st1
    ja .post_while
    ; free up st0
    ffree st0
    ;compare x and max value
    ;mov eax, [x]                                                           ; put x in eax
    ;cmp eax, max_val                                                       ; compare x and max value
    ;jg .start                                                              ; if x is greater than max value, jump up to start (loop to start)
    ; compare against max value, if max is less than input jump back to .start label without counting it
    fld qword [x]
    fld qword [max_val]
    fcomip st0, st1
    jb .start

    ;free up st0
    ffree st0
    ; else calculate sum
    ;mov eax, [sum]
    ;add eax, [x]
    ;mov [sum], eax
    ; calculate sum
    fld qword [sum]
    fld qword [x]
    fadd
    fstp qword [sum]

    ; update counter
    mov eax, [count]
    add eax, 1
    mov [count], eax
    jmp .start                                                              ; loop back to start

; after loop
.post_while:
    ; special check: if count = 0 that means no valid numbers have been received by user, then jump down to .special label
    ;mov eax, [count]
    ;mov ebx, 0
    ;cmp eax, ebx
    ;je .special

    ; calculate the average (sum/count) 
    ;mov eax, [sum]
    ;mov ebx, [count]
    ;cdq
    ;div ebx
    ;mov [avg], eax
    ; calculate average
    fld qword [sum]
    fild dword [count]
    fdiv
    fstp qword [avgc]

    ; calculate rounding (closer to below or above) i.e. 1.3 is closer to 1 so avg is 1
    ;mov eax, edx
    ;mov ebx, 2
    ;mul ebx
    ;cmp eax, [count] 
    ;jnge .dontadd                                                          ; if not greater i.e. 1.3, then jump down to .dontadd label
    ; else add one to the average
    ;mov eax, [avg]             
    ;add eax, 1
    ;mov [avg], eax

    ; setup counter and index counters
    mov ecx, 201
    mov esi, 0
    mov edi, 0
.roundloop:                                 ; loop that rounds the average to nearest integer
    ; caluclate if going to increase edi (which is used for avg array *integer array*), if ecx is divisible by 2, then increase it.
    mov eax, ecx
    mov ebx, 2
    cdq
    div ebx
    mov ebx, 0
    cmp edx, ebx
    jne .dontinc
    inc edi
.dontinc:
    ; calculate if avga at index esi is above avgc (average calculate value), if so found where it is and end loop
    fld qword [avgc]
    fld qword [avga+esi]
    ;fld qword [three]
    fcomip st0, st1
    ja .endrloop

    ; increment esi by 8
    mov eax,esi
    mov ebx, 8
    add eax, ebx
    mov esi, eax
    loop .roundloop
.endrloop:
    mov ebx, edi ; save edi index of avg (integer array)
; means it is not closer to next integer
.dontadd:
    push ebx
    ; output count
    push dword [count]
    push dword countout
    call printf
    add esp, 8
    pop ebx
    push ebx
    ; output sum
    push dword [sum+4]
    push dword [sum]
    push dword sumoutput
    call printf
    add esp, 12

    ; output average
    pop ebx
    mov eax, ebx
    mov ebx, 4
    mul ebx
    mov ebx, eax
    push dword [avg+ebx]
    push dword avgoutput
    call printf
    add esp, 8
    jmp .regular                                                            ; output should be normal, since we got to here.
; special case where count == 0, meaning no valid numbers have been inputted
.special: ; not used in testing purposes at the moment
    ; output special goodbye message
    push dword ln
    push dword fn
    push dword specialbye
    call printf
    add esp, 12
    jmp .small                                                              ; now small jump to skip rest of output

.regular:
    ; output regular bye message
    push dword ln
    push dword fn
    push dword bye
    call printf
    add esp, 12

; small jump used only in special case
.small:
    mov     esp, ebp    ; takedown stack frame
    pop     ebp         ; same as "leave" op

    mov     eax,0       ; normal, no error, return value
    ret                 ; return

很高兴您找到了解决方案!
你能告诉我们为什么你用艰难的方式做了以下事情吗?

.setavg:                            ;average array set up (used to output)
mov [avg+ebx], eax
push eax
mov eax, ebx
add eax, 4
mov ebx, eax
pop eax
add eax, 1
loop .setavg

普通版

.setavg:                            ;average array set up (used to output)
mov [avg+ebx], eax
ADD EBX, 4
add eax, 1
loop .setavg