i'm trying to calculate my download speed, and i'm doing this by dividing the size of a file(bytes) by 1024 to get it to kilobytes, then dividing by the number of seconds it took.
heres how it looks in c++
sprintf(buf, "%s - MyDownloadSpeed: %.2fkb per second", buf, (float)(filesize/total_milliseconds*1000));
so I need to divide filesize by another number using floating point. I'm unable to use the code above as it uses libc stuff and I want to avoid that. also I need the value returned from the floating point code to be in a dword since apparently wsprintf doesn't support floating point, that and having it in a dword will be easier to work with, heres what I found on the board but this doesn't do everything I want.
.data
Float1 REAL4 80.5 ;80 kilobytes
Floar2 REAL4 8.2 ;8 seconds
.code
finit
fld Float1
fdiv Floar2
no idea what to do now
this isn't my code btw credits to the original author
I think this is all correct, but right after waking up it's sometimes hard to know :lol
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
res REAL8 0.0
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
KBsi proc bytes:DWORD, ms:DWORD
fild bytes ; ST=bytes
fld8 1024.0 ; ST=1024,ST(1)=bytes
fdiv ; ST=ST(1)/ST=bytes/1024=KB
fild ms ; ST=ms,ST(1)=KB
fld8 1000.0 ; ST=1000,ST(1)=ms,ST(2)=KB
fdiv ; ST=ST(1)/ST=ms/1000=s,ST(1)=KB
fdiv ; ST=ST(1)/ST=KB/s,ST(1-7) empty
push eax ; create space on stack
fistp DWORD PTR [esp] ; store KB/s, ST-ST(7) empty
pop eax ; store in eax
ret
KBsi endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
KBs proc bytes:DWORD, ms:DWORD
fild bytes ; ST=bytes
fld8 1024.0 ; ST=1024,ST(1)=bytes
fdiv ; ST=ST(1)/ST=bytes/1024=KB
fild ms ; ST=ms,ST(1)=KB
fld8 1000.0 ; ST=1000,ST(1)=ms,ST(2)=KB
fdiv ; ST=ST(1)/ST=ms/1000=s,ST(1)=KB
fdiv ; ST=ST(1)/ST=KB/s,ST(1) empty
ret ; leave result in ST, ST(1-7) empty
KBs endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
show MACRO bytes, ms
print ustr$(bytes),9
print ustr$(ms),9
invoke KBsi, bytes, ms
print ustr$(eax), 9
invoke KBs, bytes, ms
fstp res
invoke crt_printf,chr$("%f%c"), res, 10
ENDM
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
print "bytes ms int fp",13,10
show 1024, 1000
show 1024*2, 1000
show 1024*10, 1000*2
show 1024*10, 1000
show 1000, 1000
show 1800, 1200
show 1900, 1200
show 900, 2000
show 1100, 2000
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
bytes ms int fp
1024 1000 1 1.000000
2048 1000 2 2.000000
10240 2000 5 5.000000
10240 1000 10 10.000000
1000 1000 1 0.976563
1800 1200 1 1.464844
1900 1200 2 1.546224
900 2000 0 0.439453
1100 2000 1 0.537109
Fantastic!! thanks alot michaelW, your time and effort to answer mine and others questions is always highly appreciated. Great things come to people like you!!
one last question as all that code works perfect and I edited to fit my needs, i'm struggling with returning the QWORD value to the calling function though
.data
myreturn REAL 8 0.0
.code
invoke GetSpeed,1024,myreturn
;myreturn always returns 0
GetSpeed proc one:DWORD,returnx:QWORD
;do stuff
fstp returnx
ret
GetSpeed endp
I ran into this problem with dwords aswell and fixed it by doing
eax ;contains the value I want to return
mov edx,returnx
mov [edx],eax
My code returned the floating-point value in ST as the CRT functions do. In your code the:
fstp returnx
Is assembling to:
fstp qword ptr [ebp+0Ch]
Which will store the value from ST to the stack at the address of returnx, but as soon as the procedure returns and the arguments are removed from the stack, the value will effectively be discarded. For the procedure to store the value from ST to myreturn, you must pass the address of myreturn and code the fstp instruction to store the value from ST at that address. Something like this:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
myreturn REAL8 0.0
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
ReturnPi proc pRet:DWORD
mov eax, pRet
fldpi
fstp QWORD PTR [eax]
ret
ReturnPi endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke ReturnPi, ADDR myreturn
invoke crt_printf, chr$("%f%c"), myreturn, 10
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
If you need the answer in a dword, why not simply use integer instructions?
mov eax,filesize ;in bytes
mov ecx,1000
mul ecx
div total_milliseconds
shr eax,10
EAX now contains your download speed in kbytes/second. If you want your answer in bytes/second, don't use that last shr instruction.
Quote from: MichaelW on February 24, 2008, 12:38:08 AM
My code returned the floating-point value in ST as the CRT functions do. In your code the:
fstp returnx
Is assembling to:
fstp qword ptr [ebp+0Ch]
Which will store the value from ST to the stack at the address of returnx, but as soon as the procedure returns and the arguments are removed from the stack, the value will effectively be discarded. For the procedure to store the value from ST to myreturn, you must pass the address of myreturn and code the fstp instruction to store the value from ST at that address. Something like this:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
myreturn REAL8 0.0
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
ReturnPi proc pRet:DWORD
mov eax, pRet
fldpi
fstp QWORD PTR [eax]
ret
ReturnPi endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke ReturnPi, ADDR myreturn
invoke crt_printf, chr$("%f%c"), myreturn, 10
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
Great! thanks again MichealW, I really appreciate how you explain things vs just giving an answer, kind of plays into the give a man a fish, feed him for a day, teach a man how to catch fish, feed him for a life time, quote :D also raymond floating point allows for alot more accurate results which thanks to MichealW I have now.
Quotefloating point allows for alot more accurate results
As I mentioned, if you dont use the last shr instruction, you get the result in bytes per second with simple code. How much more accurate than THAT do you need?
Remember also that the overall relative accuracy will be a direct function of the relative precision of your timing result. For example, if your measured download time is 10 seconds and you can be certain that it is
really precise to +/- 1 ms, the final result can not be any more accurate than 0.01%. Thus, if you download a 1Mb file during that period, the computed download speed would only be accurate to +/-100 bytes/second.
raymond alot of times the speed will be like 20.8 kb/s or 1.2 mb/s so I need floating point to show that extra information as it's important, showing just 1 mb/s isn't accurate obviously as it cuts out that extra 200kbs. Also I see no reason for you to be against this topic as it's very useful to understanding floating point better.
QuoteI see no reason for you to be against this topic
I have absolutely nothing against this topic. My record would show that I have made a significant contribution for the use of floating point instructions. I simply wanted to point out that
a) using floats is not always necessary to obtain the required precision,
b) the use of simple integer instructions to obtain the required result should be considered when appropriate,
c) the overall precision is relative to the parameter with the least precision (such as multiplying the diameter of a circle by 3.14 and printing the circumference with 15 significant digits using extended double precision floats is ridiculous).
BTW I still don't understand the importance of getting 20.8 kb/s with floats vs 20 kb/s with integer math. If that extra decimal is super important, then reporting in bytes/s would certainly provide the required goal. Similarly, if reporting 1227 kb/s with integer math is not sufficiently informative, ...
Quote from: raymond on February 25, 2008, 04:10:53 AM
QuoteI see no reason for you to be against this topic
BTW I still don't understand the importance of getting 20.8 kb/s with floats vs 20 kb/s with integer math. If that extra decimal is super important, then reporting in bytes/s would certainly provide the required goal. Similarly, if reporting 1227 kb/s with integer math is not sufficiently informative, ...
it is that important because myself and probably most everyone else would much rather read 20.8kb than 21299.2 bytes, at a glance thinking 1024 bytes in 1 kb I see that as 21kbs but obviously that's incorrect, so the floating is very necessary,useful, and required. Your approach "well you don't need to be so accurate" doesn't hold weight at all in this case and others.Say you made $20.8 a hour, worked 40 hours a week, that's $832 weekly, but using your approach and doing just 20 x 40 = 800...so that's $32 you'd be missing out on heh.
You could use a scaled integer to improve the resolution, and still use wsprintf. For simplicity this code simply truncates the value after the first decimal digit.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
res REAL8 0.0
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
kbs$ MACRO bytes, ms
LOCAL rvstring
.data
rvstring db 21 dup (0)
align 4
.code
; ---------------------------------------------------------------
; A modification of Raymond's code using a scaling factor of 100,
; selected to allow room in the string for the decimal point.
; ---------------------------------------------------------------
mov eax, bytes
mov ecx, 100000
mul ecx
mov ecx, ms
div ecx
shr eax, 10
; ----------------------------------------------------------------
; EAX now has KB/s * 100. Convert to a string with a minimum width
; of 3 characters, padded on the left with zeros as necessary.
; ----------------------------------------------------------------
invoke wsprintf, ADDR rvstring, chr$("%03u"), eax
mov ecx, eax ; returned length
sub ecx, 2
add ecx, OFFSET rvstring ; pointer to last 2 characters
movzx eax, WORD PTR [ecx]
mov ah, al ; mov 1/10 digit to end position
mov al, '.' ; insert decimal point
mov [ecx], ax ; store in string
mov eax, OFFSET rvstring
EXITM <eax> ; return address of string
ENDM
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
KBs proc bytes:DWORD, ms:DWORD
fild bytes ; ST=bytes
fld8 1024.0 ; ST=1024,ST(1)=bytes
fdiv ; ST=ST(1)/ST=bytes/1024=KB
fild ms ; ST=ms,ST(1)=KB
fld8 1000.0 ; ST=1000,ST(1)=ms,ST(2)=KB
fdiv ; ST=ST(1)/ST=ms/1000=s,ST(1)=KB
fdiv ; ST=ST(1)/ST=KB/s,ST(1) empty
ret ; leave result in ST, ST(1-7) empty
KBs endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
show MACRO bytes, ms
print ustr$(bytes),9
print ustr$(ms),9
print kbs$(bytes, ms),9
invoke KBs, bytes, ms
fstp res
invoke crt_printf,chr$("%f%c"), res, 10
ENDM
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
print "bytes ms int fp",13,10
show 1024, 1000
show 1024*2, 1000
show 1024*10, 1000*2
show 1024*10, 1000
show 1000, 1000
show 1800, 1200
show 1900, 1200
show 900, 2000
show 1100, 2000
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
bytes ms int fp
1024 1000 1.0 1.000000
2048 1000 2.0 2.000000
10240 2000 5.0 5.000000
10240 1000 10.0 10.000000
1000 1000 0.9 0.976563
1800 1200 1.4 1.464844
1900 1200 1.5 1.546224
900 2000 0.4 0.439453
1100 2000 0.5 0.537109