Reputation: 2911
I'm currently trying to get an average as a floating point number, rounded to the nearest .001
Being pretty new to floating point instructions and such, this is what I have so far from the reading and searching that I've done.
sum: a DWORD holding the value 90 (sum of acc number of items)
acc: a DWORD holding the value 7 (number of items)
res: a DWORD to hold the answer.
In the end, edx has the value 0. Why is this? Additionally, how do I round floating point?
Or...is there a better way to do this?
My asm:
push dword ptr sum
fild dword ptr [esp]
push dword ptr acc
fild dword ptr [esp]
add esp,4
fdiv st(0), st(1)
sub esp,4
fstp dword ptr [esp]
pop eax
add esp,4
mov edx, eax
Also, I tried this:
finit
fild sum
fidiv acc
frndint
fist res
mov eax, res
But...this results in: 2147483648 (DWORD range)
Upvotes: 3
Views: 7652
Reputation: 4650
I am not sure I understand your question correctly, but at least the 2nd bit of code seems valid. Whether it does what you want is another question. It does this:
finit
fild sum ;//ST(0) = 90
fidiv acc ;//ST(0) = ST(0) / acc = 90 / 7 = 12.857..
frndint ;//ST(0) = 13
fist res ;//RES= ST(0) = 13
mov eax, res ;//EAX = RES = 13
In other words, you are calculating round(90/7) = 13.
Now, this is a straightforward division, not an average. You'd obviously calculate an average by summing over N items and then dividing by the number of items.
The second thing is that you are working with integers, not with floating point values: the fIld
, fIdiv
and fIst
instructions work are designed to work with integer, not floating point values. If you store a value from the FPU into memory with fIst
rather than fst/fstp
this value in memory will be an integer value, not a floating point value. Is it this you want?
To store a floating point value from the FPU to memory pointed to by [eax]
, you can use
fstp dword ptr [eax] ;// Store Single-Precision Floating point value (4 bytes)
fstp qword ptr [eax] ;// Store Double-Precision Floating point value (8 bytes)
fstp tbyte ptr [eax] ;// Store Long Double-Precision Floating point value (10 bytes)
The Single and Double stores (but not the tbyte ptr
) also work with fst
instead of fstp
.
Upvotes: 1
Reputation: 26181
you seem to have a lot of unneeded stack operations in your code, however, there is a more sinister problem here, storing the fp result in a DWORD
will truncate it, so there is no point in round it unless you plan on round to the nearest integer value (which is what your second attempt does).
As such I'll base an example off your second attempt:
PUSH ECX
FILD [ESP]
PUSH EDX
FILD [ESP]
FDIV
FRNDINT
ADD ESP,4
FISTP DWORD PTR [ESP]
POP EAX
RETN
this function assumes the value in ECX
, the count in EDX
and returns a rounded average in EAX
. for here you can just change it to use your globals, or call it as a function using your globals
Upvotes: 1