计算四舍五入为整数的浮点数的平均值 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
基本上程序假设从用户输入浮点数,然后得到它们的总和,它们的平均值(从 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