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

时间:2015-03-01 18:25:55

标签: arrays assembly floating-point average nasm

基本上程序假设从用户输入浮点数,然后得到它们的总和,它们的平均值(从0.0到100.0),上面的任何东西都不计算,下面的任何东西都不算作好。负数不会被计算在内,还会退出循环/程序。输出和,输出有效数字的数量,最后输出浮点数ROUNDED到最接近的整数的平均值。我想我现在很接近,到目前为止,我的计划已经到了。 请在下面的代码中使用一些帮助找到错误/(推理错误,如果存在)。 注意我正在使用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

1 个答案:

答案 0 :(得分:0)

很高兴你找到了解决方案!
你能告诉我们你为什么要这么做吗?

.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