flat assembler
Message board for the users of flat assembler.

Index > Main > Float To String To Float. FPU-based REAL4 conversion

Author
Thread Post new topic Reply to topic
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
These are two naive routines I wrote dealing with FPU-based instructions and conversions. Quite simple and straight forward (no optimization though) manual conversions. prtflt is basically float-to-string and getflt is basically string-to-float. Thing is, since math isn't my cup of tea, i am not very convinced with the precision and the robustness. Another is with the fwait instruction - when should I use it and where? I skipped it entirely and nothing happen so far :p

You are welcome to try and give suggestions especially on the precision and the 'naive' part. This is the entire complete file.

Code:
format pe console
include 'win32axp.inc'

        ;stdcall getflt,v
        stdcall prtflt,[v],0,1 ;No precision
        stdcall prtflt,[v],3,1 ;3 precision

done:   invoke system,"pause>nul"
        invoke exit,0

;Test Data
v dd -31.221336
;v dd 15.0356565
;v dd 1.18e-38
;v dd 0.002654
;v dd -0.00000000004567
;v dd +0.0
;v dd -4294967295.0
;v dd 2147483647.0
;--------------------------------------
;Float to string
;DISPLAY FP (REAL4)
;info : [dd] (initialize to 0.0)
;     : reg32,fp constant
;     : Takes and displays e format
;pt   : Decimal places (max=6) rounding
;     : 0 - no rounding
;nline: 0-no line
;--------------------------------------
proc prtflt,info,pt,nline
        locals
           frac db 0    ;marker
           both db 0    ;marker
           big db 0     ;marker
           small db 0   ;marker
           large db 0   ;marker
           num dd 0     ;integral part
           num2 dd 0    ;fraction part
           idx dd 0     ;for small
           ndx dd 1     ;For big and large
           exponent dd 0
           mantissa dd 0.0
           copy dd 0.0
           y dd 10.0    ;divisor/multiplier
           tst dd 1,1000000,100000,\
                  10000,1000,100,10
        endl
        pushad
        finit
        fld [info]
        fstp [copy]
.back:  finit
        fld [copy]
        mov eax,[copy]
        .if eax=0 | eax=80000000h
            jmp .w
        .endif
        test eax,80000000h
             jns .p
        fchs
.p:     fxtract
        fstp [mantissa]
        fistp [exponent]
        mov ecx,[exponent]
        mov edi,[mantissa]
        and edi,7fffffh
        bts edi,23
        bsr esi,edi
        xor eax,eax
        .if [idx]   ;if returning
            jmp .dnorm
        .endif
        test ecx,ecx
             js .small
        .if ecx > 22 ;> 30
            mov [large],1
            jmp .norm
        .endif
;DENORMALIZE ----------------
;Get positional values (base-2)
.dnorm: bt edi,esi
           jc .plus
.ok:    inc ebx
        dec esi
        test ecx,ecx
             jz .big
        dec ecx
        jmp .dnorm
.plus:  mov edx,1
        shl edx,cl
        add eax,edx
        jmp .ok
;NORMALIZE -----------------
;Get: values x 2^exp * mantissa
.norm:  fld1 ;2^ecx
.x:     f2xm1
        fst st1
        fadd st0,st1
        loop .x    ;answer in ST0
        fld [mantissa]
        fmul st0,st1
        fstp [num]
        fld [num]
        fstp [copy]
        mov eax,[num]
;FOR BIG EXPONENT------------
;Find E and normalize to x.xxxxx
.big:   mov [num],eax
        .if [num] < 10000000
            xor eax,eax
            jmp .frctn
        .endif
        mov [big],1  ;marker up
.f:     fld [y]
        fld [num]
        fdiv st0,st1
        fst [num]
        fcomp [y]
        fstsw ax
        sahf
           jb .g
        inc [ndx]
        finit
        jmp .f
.g:     fld [num]
        fstp [copy]
        jmp .back
;FOR SMALL NEGATIVE EXPONENT---------
;Find E- and normalize to x.xxxxx
.small: mov eax,[info]
        mov [num2],eax
        test eax,eax
             jns .s
        fld [num2]
        fchs ;change sign
        fstp [num2]
.s:     fld [num2]
        fmul [y]
        fst [num2]
        fcomp [y]
        fstsw ax
        sahf
           jae .k
        finit
        inc [idx]
        jmp .s
.k:     .if signed[idx] <= 5
            jmp .nexp
        .endif
        fld [y]
        fld [num2]
        fdiv st0,st1
        fstp [copy]
        mov [small],1  ;marker up
        jmp .back
;NEGATIVE EXPONENT-------------------
.nexp:  neg ecx
        shr edi,cl
        bsr esi,edi
        dec ecx
        xor eax,eax
;FRACTION ---------------------------
.frctn: bt edi,esi
           jc .pow1
.ko:    inc ecx
        test esi,esi
             jz .round
        dec esi
        jmp .frctn
.pow1:  mov edx,5000000 ;negative pow of 2
        shr edx,cl      ;at position CL
        add eax,edx
        jmp .ko
;DONE & ROUNDING --------------------
.round: mov [num2],eax
        .if [big] ;| [large] ;????
            jmp .w
        .endif
        ;Rounding -------------------
        push [pt]
        pop edx
        .if edx > 6
            xor edx,edx
        .endif
        fild [tst+edx*4]
        fild [num2]
        fdiv st0,st1
        frndint
        fist [num2]
        fild [tst+edx*4]
        fmul st0,st1
        fistp [num2]
        ;----------------------------
.w:     mov eax,[info]
        mov ecx,10
        test eax,eax
             jns .print
        pushad
        cinvoke putchar,dword '-'
        popad
;DISPLAY & FORMATING-----------------
.print: xor esi,esi
        .if [frac]
            mov eax,[num2]
        .else
            mov eax,[num]
        .endif
.start: xor edx,edx
        div ecx
        push edx
        inc esi
        .if [frac] ;leading-zero padding
            cmp esi,7
            je .a
        .else
            test eax,eax
            jz .prt
        .endif
        jmp .start
.a:     .if [pt] ;Trailing zero truncate
            mov edi,dword[pt]
        .endif
.prt:   pop eax
        .if [frac] & [pt] ;if passed decimal point
            test edi,edi  ;keeps popping stack
            jz .m         ;don't print
        .endif
        add al,30h
        pushad
        cinvoke putchar,eax
        popad
        dec edi
.m:     dec esi
        test esi,esi
            jz .what
        jmp .prt
.what:  .if [both]   ;if both done
            jmp .quit
        .endif
        .if ~ [frac]
            pushad
            cinvoke putchar,dword '.'
            popad
            mov [frac],1
            jmp .print
        .endif
        ;Display Scientific E ------------
        .if [big] | [large] | [small]
            pushad
            cinvoke putchar,dword 'e'
            popad
            mov [both],1
            mov [frac],0
            .if [small]
                mov eax,[idx]
                pushad
                cinvoke putchar,dword '-'
                popad
            .else
                mov eax,[ndx]
            .endif
            jmp .start
        .endif
        ;---------------------------------
.quit:  .if [nline]
            cinvoke putchar,dword 0dh
            cinvoke putchar,dword 0ah
        .endif
        popad
        ret
endp

;---------------------------------
;String to Float
;GET FP (REAL4) FROM KEYBOARD
;Convert and save to info
;info: dd (initialize to 0.0)
;    : Does not take e-format
;    : Must use FP format as input
;---------------------------------
proc getflt,info
        locals
             m dd 0
             x dd 0.0
             pow10 dd 10.0
             power dd 1.0
             val dd 0.0
             sgn db 0
        endl
        xor esi,esi
        xor edi,edi
.intg:  cinvoke getchar
        .if eax = 0ah
            jmp .start
        .endif
        .if eax = '-'
            inc [sgn]
            .if [sgn] > 1
                cinvoke putchar,dword '#'
                jmp .quit
            .endif
            jmp .intg
        .endif
        .if ~ al = '.'
            sub eax,30h
        .else
            mov edi,esi
            jmp .intg
        .endif
        push eax
        inc esi
        jmp .intg
;----------------------
.start: finit
        pop [m]
        fild [m]
        fstp [val]
        mov ecx,esi
        dec ecx
.rr:    finit
        fld [pow10] ;10^
        fld [power]
        fmul st0,st1
        fst [power]
        pop [m]
        fild [m]
        fmul st0,st1
        fld [val]
        fadd st0,st1
        fstp [val]
        loop .rr
;----------------------
        mov ecx,esi
        sub ecx,edi  ;Divide by decimal places
.d:     fld [pow10]  ;found in ecx
        fld [val]
        fdiv st0,st1
        fstp [val]
        finit
        loop .d
;----------------------
.quit:  mov eax,[info]
        mov ecx,[val]
        .if [sgn]
            bts ecx,31
        .endif
        mov [eax],ecx
        ret
endp

data import
     library msvcrt,'msvcrt.dll'
     import msvcrt,\
            system,'system',exit,'exit',\
            putchar,'putchar',getchar,'getchar'
end data
    
Post 04 Sep 2014, 10:58
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
Just in case if u want to download and try it... (refer to the latest attachment below)


Last edited by fasmnewbie on 06 Sep 2014, 06:57; edited 1 time in total
Post 04 Sep 2014, 11:21
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
A slightly better prtflt version, with character printing is done towards the end, plus fixing a precision bug when entering data such as "33.99"

Code:
proc prtflt,info,pt,nline
        locals
           s db 13 dup (' ')
           frac db 0    ;marker
           both db 0    ;marker
           big db 0     ;marker
           small db 0   ;marker
           large db 0   ;marker
           num dd 0     ;integral part
           num2 dd 0    ;fraction part
           idx dd 0     ;for small
           ndx dd 1     ;For big and large
           exponent dd 0
           mantissa dd 0.0
           copy dd 0.0
           y dd 10.0
           tst dd 1,1000000,100000,\
                  10000,1000,100,10,1
        endl
        pushad
        mov eax,[info]
        .if eax=0 | eax=80000000h
            jmp .w   ;case of signed 0.0 
        .endif
.back:  finit
        mov [copy],eax
        fld [copy]
        test eax,80000000h
             jns .p
        fchs
.p:     fxtract
        fstp [mantissa]
        fistp [exponent]
        mov ecx,[exponent]
        mov edi,[mantissa]
        and edi,7fffffh
        bts edi,23
        bsr esi,edi
        xor eax,eax
        .if [idx]    ;if returning
            jmp .dnorm
        .endif
        test ecx,ecx
             js .small
        .if ecx > 22 ;> 30
            mov [large],1
            jmp .norm
        .endif
;DENORMALIZE ----------------
;Get positional values (base-2)
.dnorm: bt edi,esi
           jc .plus
.ok:    dec esi
        test ecx,ecx
             jz .big
        dec ecx
        jmp .dnorm
.plus:  mov edx,1
        shl edx,cl
        add eax,edx
        jmp .ok
;NORMALIZE -----------------
;Get: values x 2^exp * mantissa
.norm:  fld1 ;2^ecx
.x:     f2xm1
        fst st1
        fadd st0,st1
        loop .x    ;answer in ST0
        fld [mantissa]
        fmul st0,st1
        fstp [num]
        mov eax,[num]
;FOR BIG EXPONENT------------
;Find E and normalize to x.xxxxx
.big:   mov [num],eax
        .if [num] < 1000000
            xor eax,eax
            jmp .frctn
        .endif
.f:     fld [y]
        fld [num]
        fdiv st0,st1
        fst [num]
        fcomp [y]
        fstsw ax
        sahf
           jb .g
        inc [ndx]
        finit
        jmp .f
.g:     mov eax,[num]
        mov [big],1  ;marker up
        jmp .back
;FOR SMALL NEGATIVE EXPONENT---------
;Find E- and normalize to x.xxxxx
.small: mov eax,[info]
        mov [num2],eax
        test eax,eax
             jns .s
        fld [num2]
        fchs ;change sign
        fstp [num2]
.s:     fld [num2]
        fmul [y]
        fst [num2]
        fcomp [y]
        fstsw ax
        sahf
           jae .k
        finit
        inc [idx]
        jmp .s
.k:     .if signed[idx] < 6
            jmp .nexp
        .endif
        fld [y]
        fld [num2]
        fdiv st0,st1
        fstp [copy]
        mov eax,[copy]
        mov [small],1  ;marker up
        jmp .back
;NEGATIVE EXPONENT-------------------
.nexp:  neg ecx
        shr edi,cl
        bsr esi,edi
        dec ecx
        xor eax,eax
;FRACTION ---------------------------
.frctn: bt edi,esi
           jc .pow1
.ko:    inc ecx
        test esi,esi
             jz .round
        dec esi
        jmp .frctn
.pow1:  mov edx,5000000 ;negative pow of 2
        shr edx,cl      ;at position CL
        add eax,edx
        jmp .ko
;DONE & ROUNDING --------------------
.round: mov [num2],eax
        ;.if [big]  ;don't round large exp?
        ;    jmp .w ;i don't know
        ;.endif
        ;Rounding -------------------
        mov edx,[pt]
        .if edx > 6
            xor edx,edx
        .endif
        fild [tst+edx*4]
        fild [num2]
        fdiv st0,st1
        frndint
        fist [num2]
        fild [tst+edx*4]
        fmul st0,st1
        fistp [num2]
        .if edx = 1 & [num2] >= 10000000
            mov [num2],eax
        .endif
        ;----------------------------
.w:     mov eax,[info]
        mov ecx,10
        xor edi,edi  ;for string
        test eax,eax
             jns .print
        mov [s+edi],'-'
        inc edi
;DISPLAY & FORMATING-----------------
.print: xor esi,esi
        .if [frac]
            mov eax,[num2]
        .else
            mov eax,[num]
        .endif
.start: xor edx,edx
        div ecx
        push edx
        inc esi
        .if [frac] ;leading-zero padding
            cmp esi,7
            je .a
        .else
            test eax,eax
            jz .prt
        .endif
        jmp .start
.a:     .if [pt] ;Trailing zero truncate
            mov ebx,dword[pt]
        .endif
.prt:   pop eax
        .if [frac] & [pt] ;if passed decimal point
            test ebx,ebx  ;keeps popping stack
            jz .m         ;don't print
        .endif
        add al,30h
        mov byte[s+edi],al
        inc edi
        dec ebx
.m:     dec esi
        test esi,esi
            jz .what
        jmp .prt
.what:  .if [both]   ;if both done
            jmp .quit
        .endif
        .if ~ [frac]
            mov byte[s+edi],'.'
            inc edi
            mov [frac],1
            jmp .print
        .endif
        ;Display Scientific E ------------
        .if [big] | [large] | [small]
            mov [both],1
            mov [frac],0
            .if [small]
                mov word[s+edi],'e-'
                add edi,2
                mov eax,[idx]
            .else
                mov word[s+edi],'e+'
                add edi,2
                mov eax,[ndx]
            .endif
            jmp .start
        .endif
        ;---------------------------------
.quit:  dec edi
        xor esi,esi
.disp:  mov al,byte[s+esi]
        cinvoke putchar,eax
        cmp esi,edi
            je .out
        inc esi
        jmp .disp
.out:   .if [nline]
            cinvoke putchar,0d0ah
        .endif
        popad
        ret
endp    
Post 05 Sep 2014, 19:26
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
The entire file... with corrected prtflt and unverified getflt...

Code:
format pe console
include 'win32axp.inc'

        mov ecx,8
        xor esi,esi
.go:    stdcall prtflt,[v+esi*4],0,1  ;no precision
        stdcall prtflt,[v+esi*4],1,1  ;1 precision
        stdcall prtflt,[v+esi*4],3,1  ;3 precisions
        stdcall prtflt,[v+esi*4],5,1  ;5 precisions
        inc esi
        loop .go

.done:  invoke system,"pause>nul"
        invoke exit,0

;Test Data
v dd 4294967295.0
  dd 33.99
  dd -31.221336
  dd 15.0356565
  dd 1.18e-38
  dd 0.002654
  dd -0.00000000004567
  dd -0.0

;--------------------------------------
;Float to string
;DISPLAY FP (REAL4)
;info : [dd] (initialize to 0.0)
;     : reg32,fp constant
;     : Takes and displays e format
;pt   : Decimal places (max=6) rounding
;     : 0 - no rounding
;nline: 0-no line
;--------------------------------------
proc prtflt,info,pt,nline
        locals
           s db 13 dup (' ')
           frac db 0    ;marker
           both db 0    ;marker
           big db 0     ;marker
           small db 0   ;marker
           large db 0   ;marker
           num dd 0     ;integral part
           num2 dd 0    ;fraction part
           idx dd 0     ;for small
           ndx dd 1     ;For big and large
           exponent dd 0
           mantissa dd 0.0
           copy dd 0.0
           y dd 10.0
           tst dd 1,1000000,100000,\
                  10000,1000,100,10,1
        endl
        pushad
        mov eax,[info]
        .if eax=0 | eax=80000000h
            jmp .w  ;case of signed 0.0
        .endif
.back:  finit
        mov [copy],eax
        fld [copy]
        test eax,80000000h
             jns .p
        fchs
.p:     fxtract
        fstp [mantissa]
        fistp [exponent]
        mov ecx,[exponent]
        mov edi,[mantissa]
        and edi,7fffffh
        bts edi,23
        bsr esi,edi
        xor eax,eax
        .if [idx]    ;if returning
            jmp .dnorm
        .endif
        test ecx,ecx
             js .small
        .if ecx > 22 ;> 30
            mov [large],1
            jmp .norm
        .endif
;DENORMALIZE ----------------
;Get positional values (base-2)
.dnorm: bt edi,esi
           jc .plus
.ok:    dec esi
        test ecx,ecx
             jz .big
        dec ecx
        jmp .dnorm
.plus:  mov edx,1
        shl edx,cl
        add eax,edx
        jmp .ok
;NORMALIZE -----------------
;Get: values x 2^exp * mantissa
.norm:  fld1 ;2^ecx
.x:     f2xm1
        fst st1
        fadd st0,st1
        loop .x    ;answer in ST0
        fld [mantissa]
        fmul st0,st1
        fstp [num]
        mov eax,[num]
;FOR BIG EXPONENT------------
;Find E and normalize to x.xxxxx
.big:   mov [num],eax
        .if [num] < 1000000
            xor eax,eax
            jmp .frctn
        .endif
.f:     fld [y]
        fld [num]
        fdiv st0,st1
        fst [num]
        fcomp [y]
        fstsw ax
        sahf
           jb .g
        inc [ndx]
        finit
        jmp .f
.g:     mov eax,[num]
        mov [big],1  ;marker up
        jmp .back
;FOR SMALL NEGATIVE EXPONENT---------
;Find E- and normalize to x.xxxxx
.small: mov eax,[info]
        mov [num2],eax
        test eax,eax
             jns .s
        fld [num2]
        fchs ;change sign
        fstp [num2]
.s:     fld [num2]
        fmul [y]
        fst [num2]
        fcomp [y]
        fstsw ax
        sahf
           jae .k
        finit
        inc [idx]
        jmp .s
.k:     .if signed[idx] < 6
            jmp .nexp
        .endif
        fld [y]
        fld [num2]
        fdiv st0,st1
        fstp [copy]
        mov eax,[copy]
        mov [small],1  ;marker up
        jmp .back
;NEGATIVE EXPONENT-------------------
.nexp:  neg ecx
        shr edi,cl
        bsr esi,edi
        dec ecx
        xor eax,eax
;FRACTION ---------------------------
.frctn: bt edi,esi
           jc .pow1
.ko:    inc ecx
        test esi,esi
             jz .round
        dec esi
        jmp .frctn
.pow1:  mov edx,5000000 ;negative pow of 2
        shr edx,cl      ;at position CL
        add eax,edx
        jmp .ko
;DONE & ROUNDING --------------------
.round: mov [num2],eax
        ;.if [big]  ;don't round large exp?
        ;    jmp .w ;i don't know
        ;.endif
        ;Rounding -------------------
        mov edx,[pt]
        .if edx > 6
            xor edx,edx
        .endif
        fild [tst+edx*4]
        fild [num2]
        fdiv st0,st1
        frndint
        fist [num2]
        fild [tst+edx*4]
        fmul st0,st1
        fistp [num2]
        .if edx = 1 & [num2] >= 10000000
            mov [num2],eax
        .endif
        ;----------------------------
.w:     mov eax,[info]
        mov ecx,10
        xor edi,edi  ;for string
        test eax,eax
             jns .print
        mov [s+edi],'-'
        inc edi
;DISPLAY & FORMATING-----------------
.print: xor esi,esi
        .if [frac]
            mov eax,[num2]
        .else
            mov eax,[num]
        .endif
.start: xor edx,edx
        div ecx
        push edx
        inc esi
        .if [frac] ;leading-zero padding
            cmp esi,7
            je .a
        .else
            test eax,eax
            jz .prt
        .endif
        jmp .start
.a:     .if [pt] ;Trailing zero truncate
            mov ebx,dword[pt]
        .endif
.prt:   pop eax
        .if [frac] & [pt] ;if passed decimal point
            test ebx,ebx  ;keeps popping stack
            jz .m         ;don't print
        .endif
        add al,30h
        mov byte[s+edi],al
        inc edi
        dec ebx
.m:     dec esi
        test esi,esi
            jz .what
        jmp .prt
.what:  .if [both]   ;if both done
            jmp .quit
        .endif
        .if ~ [frac]
            mov byte[s+edi],'.'
            inc edi
            mov [frac],1
            jmp .print
        .endif
        ;Display Scientific E ------------
        .if [big] | [large] | [small]
            mov [both],1
            mov [frac],0
            .if [small]
                mov word[s+edi],'e-'
                add edi,2
                mov eax,[idx]
            .else
                mov word[s+edi],'e+'
                add edi,2
                mov eax,[ndx]
            .endif
            jmp .start
        .endif
        ;---------------------------------
.quit:  dec edi
        xor esi,esi
.disp:  mov al,byte[s+esi]
        cinvoke putchar,eax
        cmp esi,edi
            je .out
        inc esi
        jmp .disp
.out:   .if [nline]
            cinvoke putchar,0d0ah
        .endif
        popad
        ret
endp

;---------------------------------
;String to Float
;GET FP (REAL4) FROM KEYBOARD
;Convert and save to info
;info: dd (initialize to 0.0)
;    : Does not take e-format
;    : Must use FP format as input
;---------------------------------
proc getflt,info
        locals
             m dd 0
             x dd 0.0
             pow10 dd 10.0
             power dd 1.0
             val dd 0.0
             sgn db 0
        endl
        xor esi,esi
        xor edi,edi
.intg:  cinvoke getchar
        .if eax = 0ah
            jmp .start
        .endif
        .if eax = '-'
            inc [sgn]
            jmp .intg
        .endif
        .if ~ al = '.'
            sub eax,30h
        .else
            mov edi,esi
            jmp .intg
        .endif
        push eax
        inc esi
        jmp .intg
;----------------------
.start: finit
        pop [m]
        fild [m]
        fstp [val]
        mov ecx,esi
        dec ecx
.rr:    finit
        fld [pow10] ;10^
        fld [power]
        fmul st0,st1
        fst [power]
        pop [m]
        fild [m]
        fmul st0,st1
        fld [val]
        fadd st0,st1
        fstp [val]
        loop .rr
;----------------------
        mov ecx,esi
        sub ecx,edi  ;Divide by decimal places
.d:     fld [pow10]  ;found in ecx
        fld [val]
        fdiv st0,st1
        fstp [val]
        finit
        loop .d
;----------------------
.quit:  mov eax,[info]
        mov ecx,[val]
        .if [sgn]
            bts ecx,31
        .endif
        mov [eax],ecx
        ret
endp

data import
     library msvcrt,'msvcrt.dll'
     import msvcrt,\
            system,'system',exit,'exit',\
            putchar,'putchar',getchar,'getchar'
end data    


With following output...

Code:
4.2949665e+9
4.3e+9
4.295e+9
4.29497e+9
33.9900014
33.9
33.990
33.99000
-31.2213361
-31.2
-31.221
-31.22134
15.0356567
15.0
15.036
15.03566
1.1799995e-38
1.2e-38
1.180e-38
1.18000e-38
0.0026535
0.0
0.003
0.00265
-4.5669986e-11
-4.6e-11
-4.567e-11
-4.56700e-11
-0.0000000
-0.0
-0.000
-0.00000    


Need advise whether these precision are within acceptable range and any other issues that I am not aware of.

EDIT: download deleted. See below.


Last edited by fasmnewbie on 11 Sep 2014, 16:57; edited 1 time in total
Post 05 Sep 2014, 19:42
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
A little correction to prtflt- Fixing incorrect display when data is 1000000.00.
Plus, a little optimization and code clean-up.

Code:
proc prtflt,info,pt,nline
        locals
           tst dd 1,1000000,100000,\
                  10000,1000,100,10
           s db 14 dup (?)
           frac db 0    ;marker
           both db 0    ;marker
           big db 0     ;marker
           small db 0   ;marker
           large db 0   ;marker
           num dd 0     ;integral part
           num2 dd 0    ;fraction part
           idx dd 0     ;for small
           ndx dd 1     ;For big and large
           exponent dd 0
           mantissa dd 0.0
           copy dd 0.0
           y dd 10.0
           one dd 1.0
        endl
        pushad
        mov eax,[info]
        .if eax=0 | eax=80000000h
            jmp .w  ;case of signed 0.0
        .endif
.back:  finit
        mov [copy],eax
        fld [copy]
        test eax,80000000h
        jns .p
        fchs
.p:     fxtract
        fstp [mantissa]
        fistp [exponent]
        mov ecx,[exponent]
        mov edi,[mantissa]
        and edi,7fffffh
        bts edi,23
        bsr esi,edi
        xor eax,eax
        cmp [idx],1   ;if returning
            je .dnorm
        test ecx,ecx
             js .small
        cmp ecx,22
            ja .norm
;DENORMALIZE ----------------
;Get positional values (base-2)
.dnorm: bt edi,esi
           jc .plus
.ok:    dec esi
        test ecx,ecx
             jz .big
        dec ecx
        jmp .dnorm
.plus:  mov edx,1
        shl edx,cl
        add eax,edx
        jmp .ok
;NORMALIZE -----------------
;Get: values x 2^exp * mantissa
.norm:  fld1 ;2^ecx
.x:     f2xm1
        fst st1
        fadd st0,st1
        loop .x    ;answer in ST0
        fld [mantissa]
        fmul st0,st1
        fstp [num]
        mov eax,[num]
        mov [large],1
;FOR BIG EXPONENT------------
;Find E and normalize to x.xxxxx
.big:   mov [num],eax
        xor eax,eax
        cmp [num],10000000
            jb .frctn
.f:     fld [y]
        fld [num]
        fdiv st0,st1
        fst [num]
        fcomp [y]
        fstsw ax
        sahf
           jb .g
        inc [ndx]
        finit
        jmp .f
.g:     mov eax,[num]
        mov [big],1  ;marker up
        jmp .back
;FOR SMALL NEGATIVE EXPONENT---------
;Find E- and normalize to x.xxxxx
.small: mov eax,[info]
        mov [num2],eax
        test eax,eax
             jns .s
        fld [num2]
        fchs ;change sign
        fstp [num2]
.s:     fld [num2]
        fmul [y]
        fst [num2]
        inc [idx]
        fcomp [one]
        fstsw ax
        sahf
        jae .k
        finit
        jmp .s
.k:     cmp [idx],6
            jl .nexp
        mov eax,[num2]
        mov [small],1  ;marker up
        jmp .back
;NEGATIVE EXPONENT-------------------
.nexp:  neg ecx
        shr edi,cl
        bsr esi,edi
        dec ecx
        xor eax,eax
;FRACTION ---------------------------
.frctn: bt edi,esi
           jc .pow1
.ko:    inc ecx
        test esi,esi
             jz .round
        dec esi
        jmp .frctn
.pow1:  mov edx,5000000 ;negative pow of 2
        shr edx,cl      ;at position CL
        add eax,edx
        jmp .ko
;DONE & ROUNDING --------------------
.round: mov [num2],eax
        ;cmp [big],1  ;don't round large exp?
        ;    je .w ;i don't know
        ;Rounding -------------------
        mov edx,[pt]
        .if edx > 6
            xor edx,edx
        .endif
        fild [tst+edx*4]
        fild [num2]
        fdiv st0,st1
        frndint
        fist [num2]
        fild [tst+edx*4]
        fmul st0,st1
        fistp [num2]
        .if edx = 1 & [num2] >= 10000000
            mov [num2],eax
        .endif
        ;----------------------------
.w:     mov eax,[info]
        mov ecx,10
        lea edi,[s]
        test eax,eax
             jns .print
        mov al,'-'
        stosb
;SAVE STRING TO STACK
.print: xor esi,esi
        mov eax,[num]
        cmp [frac],1
            jne .start
        mov eax,[num2]
.start: xor edx,edx
        div ecx
        push edx
        inc esi
        .if [frac] ;zero padding
            cmp esi,7
            je .prt
        .else
            test eax,eax
            jz .prt
        .endif
        jmp .start
;CONVERT TO ASCII & SAVE TO STRING
.prt:   pop eax
        add al,30h
        stosb
.m:     dec esi
        test esi,esi
            jz .what
        jmp .prt
.what:  cmp [both],1
            je .quit
        .if ~ [frac]
            mov al,'.'
            stosb
            mov [frac],1
            jmp .print
        .endif
        ;Scientific E ------------
        .if [big] | [large] | [small]
            mov [both],1
            mov [frac],0
            .if [small]
                mov ax,'e-'
                stosw
                mov eax,[idx]
            .else
                mov ax,'e+'
                stosw
                mov eax,[ndx]
            .endif
            jmp .start
        .endif
;DISPLAY -------------------------
.quit:  xor al,al  ;terminal byte
        stosb
        xor edi,edi
.disp:  mov al,[s+edi]
        test al,al
             jz .out
        .if al='.' & [pt]
            mov esi,7
            sub esi,[pt]
            mov ebx,[pt]
            add ebx,edi
        .endif
        .if [pt] & ebx=edi
            add edi,esi ;trailing 0s
        .endif
.h:     cinvoke putchar,eax
        inc edi
        jmp .disp
.out:   .if [nline]
            cinvoke putchar,0d0ah
        .endif
        popad
        ret
endp    


With these output

Code:
56.9900014
56.9900
56.9
1.1799995e-38
1.1800e-38
1.2e-38
1234567.0000000
1234567.0000
1234567.0
1.0000000e+7
1.0000e+7
1.0e+7
-36.8886984
-36.8887
-36.9
-4.5669986e-11
-4.5670e-11
-4.6e-11    
Post 06 Sep 2014, 20:51
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
Final update...hopefully. With minor fix to getflt

Below is a test when dealing with FSQRT. In this case, the value must be made absolute explicitly because the routines won't do it (I am not sure if ignoring absolute values is a good approach though). For other cases, it runs just fine so far.

Code:
format pe console
include 'win32axp.inc'

;Sample run: Find square root
stdcall getflt,val
fld [val]
fabs  ;without this, HUGE headache
fsqrt ;if entered value is negative
fstp [ans]
stdcall prtflt,[ans],0,0

invoke system,"pause>nul"
invoke exit,0
val dd 0.0
ans dd 0.0    


Output

Code:
-34.245 ;User input
5.8519228    


Description:
Download
Filename: test3.asm
Filesize: 6.04 KB
Downloaded: 177 Time(s)

Post 07 Sep 2014, 07:56
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
After some light reading on Agner Fog's material, I found out that instruction F2XM1 has a large latency. You can change the NORMALIZE part from this;

Code:
;NORMALIZE ----------------- 
;Get: values x 2^exp * mantissa 
.norm:  fld1 ;2^ecx 
.x:     f2xm1 
        fst st1 
        fadd st0,st1 
        loop .x    ;answer in ST0 
        fld [mantissa] 
        fmul st0,st1 
        fstp [num] 
        mov eax,[num] 
        mov [large],1    


To this...

Code:
;NORMALIZE -----------------
;Get: mantissa * 2^exp
.norm:  mov [copy],ecx
        fild [copy] ;exp
        fld1
        fscale
        fst [copy]
        fld [mantissa]
        fmul st0,st1
        fstp [num]
        mov eax,[num]
        mov [large],1    


Sorry for the naivity. I am a learner myself.
Post 11 Sep 2014, 16:54
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie
This is a fully working, interactive and complete program and routines demonstrating FPU-based conversion (float-to-string and string-to-float), plus a prtstr as a bonus. No other external dependencies except putchar and getchar.

Code:
format pe console
include 'win32axp.inc'

stdcall prtstr,"Hello folks. This is a test program.\n"
stdcall prtstr,"Enter a radian in FP value and I'll\nconvert it to SINE"
stdcall prtstr,"\n\nRADIAN? "
stdcall getflt,rad
finit
fld [rad]
fsin
fstp [ans]
stdcall prtstr,"SINE is: "
stdcall prtflt,[ans],4,1  ;4 precision points,new line
stdcall prtstr,"Done.\n"

invoke system,"pause>0"
invoke exit,0

rad dd 0.0
ans dd 0.0     


Output:
Code:
Hello folks. This is a test program.
Enter a radian in FP value and I'll
convert it to SINE

RADIAN? 34.5224  ;user input
SINE is: 0.0351
Done.    


Hope this can bring benefits to newbies. New file download here. Further bug fixes and optimization is up to you. LOL

EDIT: a little correction LOL. Just embracing pushad and popad around putchar.


Description: A corrected attachment. A sample program, prtflt, getflt and prtstr are all here.
Download
Filename: test4.asm
Filesize: 5.79 KB
Downloaded: 181 Time(s)

Post 11 Sep 2014, 17:52
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.