News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

floating point

Started by ecube, February 23, 2008, 08:57:35 AM

Previous topic - Next topic

ecube

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

MichaelW

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

eschew obfuscation

ecube

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!!

ecube

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

MichaelW

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

eschew obfuscation

raymond

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.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

ecube

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.

raymond

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.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

ecube

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.

raymond

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, ...
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

ecube

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.

MichaelW

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

eschew obfuscation