flat assembler
Message board for the users of flat assembler.

Index > Main > FASMLIB (FASM Standard Library Project)

Goto page Previous  1, 2, 3, 4, 5  Next
Author
Thread Post new topic Reply to topic
Reverend



Joined: 24 Aug 2004
Posts: 408
Location: Poland
Reverend 09 Feb 2007, 22:18
This topic hooked me, and I wrote today a version that reads the float number directly as the IEEE 754 standard says. Below is the code that reads single precision only (other precision can be made by analogy):
Code:
;===============================================================================
;       routine converting float to ascii value
proc    ftoa                    value_ptr, string_ptr
locals
  status_original               dw ?
  status_changed                dw ?
endl
        mov     eax, [value_ptr]
        mov     ecx, [string_ptr]
        mov     eax, [eax]

;-------check-sign--------------------------------------------------------------
        xor     edx, edx
        test    eax, 80000000h
        jnz     .minus
  .plus:
        mov     byte [ecx], '+'
        inc     ecx
        jmp     .sign_ready
  .minus:
        mov     byte [ecx], '-'
        inc     ecx

;-------get-exponent-value------------------------------------------------------
  .sign_ready:
        mov     dword [ecx], '1 * '
        add     ecx, 4
        mov     word [ecx], '2^'
        add     ecx, 2

;       e = Exp -127
        mov     edx, eax
        and     edx, 7FFFFFFFh
        shr     edx, 23
        sub     edx, 7Fh
        jns     .not_signed
        mov     byte [ecx], '('
        inc     ecx

  .not_signed:
        push    eax  ecx
        stdcall itoa, edx, 10, ecx, TRUE
        mov     edx, eax
        pop     ecx  eax
        cmp     byte [ecx - 1], '('
        jnz     .not_signed2
        add     ecx, edx
        mov     byte [ecx], ')'
        inc     ecx
        jmp     .exponent_ready

  .not_signed2:
        add     ecx, edx

;-------get-mantissa-value------------------------------------------------------
  .exponent_ready:
        push    ebx  edi  esi
        mov     edx, eax
        shl     edx, 32 - 23
        jz      .mantissa_ready

;       st0 - numerator - l
;       st1 - denominator - m
;       st2 - actual denominator - am
        mov     eax, 23 + 1

        fninit
        fld1
        fadd    st, st          ; 0-2
        fld1                    ; 0-1  1-2
        fld1                    ; 0-1  1-1  2-2
        fldz                    ; 0-0  1-1  2-1  3-2

  .mantissa_loop:
        dec     eax
        jz      .mantissa_loop_finish

        fxch    st2
        fmul    st, st3
        fxch    st2             ; 0-l  1-m  2-am  3-2

        shl     edx, 1
        jnc     .mantissa_loop

        fmul    st, st2         ; 0-l*am  1-m  2-am  3-2
        fadd    st, st1         ; 0-(l*am)+m  1-m  2-am  3-2

        fxch    st1
        fmul    st, st2
        fxch    st1             ; 0-(l*am)+m  1-m*am  2-am  3-2

    .parity_check:
        fld     st              ; 0-(l*am)+m  1-(l*am)+m  2-m*am  3-am  4-2
        fdiv    st, st4         ; 0-((l*am)+m)/2  1-(l*am)+m  2-m*am  3-am  4-2

;       check if it's divisable by 2
        fld     st
        frndint
        fsubp   st1, st
        fadd    st, st

        push    ebx
        fistp   dword [esp]
        pop     ebx
        test    ebx, ebx
        jnz     .mantissa_loop

;       if it's divisable, divide both numerator and denominator by 2
        fdiv    st, st3
        fxch    st1
        fdiv    st, st3
        fxch    st1

        jmp     .parity_check

  .mantissa_loop_finish:
        mov     dword [ecx], ' * 1'
        add     ecx, 4
        mov     byte [ecx], '.'
        inc     ecx

;       exchange 2 by 10
        fld1
        fadd    st, st
        fadd    st, st
        fadd    st, st
        fld1
        fadd    st, st
        faddp   st1, st
        fxch    st4
        fstp    st              ; 0-l  1-m  2-am  3-10

;       cut mantissa (no rounding)
        fnstcw  [status_original]
        mov     ax, [status_original]
        or      ax, 0000110000000000b
        mov     [status_changed], ax
        fldcw   [status_changed]

;       algorithm of integer division
  .mantissa_output_loop:
        fmul    st, st3         ; 0-10*l  1-m  2-am  3-10
        fld     st              ; 0-10*l  1-10*l  2-m  3-am  4-10
        fdiv    st, st2         ; 0-(10*l)/m  1-10*l  2-m  3-am  4-10

        push    eax
        frndint
        fist    dword [esp]
        pop     eax
        mov     al, [itoa.digits + eax]
        mov     byte [ecx], al
        inc     ecx

        fmul    st, st2         ; 0-[10*l]  1-10*l  2-m  3-am  4-10
        fsubp   st1, st         ; 0-(10*l mod m)  1-m  2-am  3-10
        ftst
        fnstsw  ax
        test    ax, 4000h
        jz      .mantissa_output_loop

        fldcw   [status_original]

  .mantissa_ready:
        pop     esi  edi  ebx
        ret
endp

;===============================================================================
;       integer to ASCII conversion procedure
;
;       input:
;       number - number to convert Smile
;       radix - base system like 10 for decimal, 16 for hexadecimal, etc.
;       result_buffer - pointer to memory where output will be saved
;       signed - bool value, if number is signed (-2147483646...2147483647)
;                or unsigned (0...4294967295)
;
;       output:
;       no immediate output
;
;       possible errors:
;       radix exceeds 16
;
;       coded by Reverend // HTB + RAG
;===============================================================================
proc    itoa                    number, radix, result_buffer, signed
locals
  temp_buffer                   rb 32+1
endl
        push    ebx  edi  esi
        mov     esi, [radix]
        lea     edi, [temp_buffer+32]
        mov     ebx, itoa.digits
        cmp     esi, 16
        ja      .error
        std
        xor     al, al
        stosb
        mov     eax, [number]
        cmp     [signed], TRUE
        jnz     @F
        test    eax, 80000000h
        jz      @F
        neg     eax
    @@:
        xor     edx, edx
        idiv    esi
        xchg    eax, edx
        xlatb
        stosb
        xchg    eax, edx
        test    eax, eax
        jnz     @B
        lea     esi, [edi+1]
        mov     edi, [result_buffer]
        cld
        cmp     [signed], TRUE
        jnz     @F
        test    [number], 80000000h
        jz      @F
        mov     al, '-'
        stosb
    @@:
        lodsb
        stosb
        test    al, al
        jnz     @B
        sub     edi, [result_buffer]
        lea     eax, [edi-1]
        stc
  .theend:
        cld
        pop     esi  edi  ebx
        ret
  .error:
        clc
        jmp     .theend
endp

idata {
        itoa.digits             db '0123456789ABCDEF'
      }    

Yes, new ftoa is very, very long. It outputs data in format: s * 2^e * m, where: s - sign, e - exponent, m - mantissa.
Code uses FPU heavily, but only for integer operations. There were really huge numbers and they just didn't fit in 32-bit register. But as I do only integer operations, no precision is lost, and thus the output is as exact as it can be.
Examples:
PI is saved as
Code:
+1 * 2^1 * 1.57079637050628662109375    
This mantissa is finite (ie. there are no other numbers after the coma). This is just as it is saved in the float, no more, no less.
Post 09 Feb 2007, 22:18
View user's profile Send private message Visit poster's website Reply with quote
Vasilev Vjacheslav



Joined: 11 Aug 2004
Posts: 392
Vasilev Vjacheslav 10 Feb 2007, 09:31
for proper rounding in ftoa maybe better to use

110000111111b

instead of:

110000000000b

?
Post 10 Feb 2007, 09:31
View user's profile Send private message Reply with quote
Vasilev Vjacheslav



Joined: 11 Aug 2004
Posts: 392
Vasilev Vjacheslav 10 Feb 2007, 09:40
if someone wants i can post my version of 'double to ascii' algo

ps. also i can post assembler equivalent of visual basic mid(), left() and right() functions, imho very useful for working with strings
Post 10 Feb 2007, 09:40
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 10 Feb 2007, 10:53
Quote:
if someone wants i can post my version of 'double to ascii' algo


That would be nice from you... Smile
Post 10 Feb 2007, 10:53
View user's profile Send private message Reply with quote
Vasilev Vjacheslav



Joined: 11 Aug 2004
Posts: 392
Vasilev Vjacheslav 10 Feb 2007, 13:28
ok, it is a mid(), left(), right() implementation in assembler

ps. a bit later i put dtoa


Description:
Download
Filename: main.asm
Filesize: 7.69 KB
Downloaded: 867 Time(s)


_________________
[not enough memory]
Post 10 Feb 2007, 13:28
View user's profile Send private message Reply with quote
dead_body



Joined: 21 Sep 2005
Posts: 187
Location: Ukraine,Kharkov
dead_body 10 Feb 2007, 18:22
what happened to some files in fasmlib?

where the directory "linux"?
Post 10 Feb 2007, 18:22
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 11 Feb 2007, 10:19
this thread is pretty old, don't mind it/
Post 11 Feb 2007, 10:19
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Vasilev Vjacheslav



Joined: 11 Aug 2004
Posts: 392
Vasilev Vjacheslav 11 Feb 2007, 14:51
here is my version of ftoa/dtoa (pretty long)


Description:
Download
Filename: ftoa.asm
Filesize: 10.04 KB
Downloaded: 919 Time(s)


_________________
[not enough memory]
Post 11 Feb 2007, 14:51
View user's profile Send private message Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 03 Jan 2008, 17:41
Reverend wrote:
Hello all
I haven't been on board for some time. Sorry guys, I promised to create the conversion procedures and was unreachable. I really had lack of time Crying or Very sad

But I have written it. Don't worry, routines are ready and heavily tested.


The ATOF routine seems to output different numbers based on how many are input.

I do some calculations based on the number stored in st0.

Here are some examples. The left number is the input (atof), and the second number is what ends up in st0.

Code:
INPUT           OUTPUT
1               1.0
1.              21.1000000000
1.0             3.00999999910
1.00            1.20099999910
1.000           1.0201000000
1.0000          1.00200999910
1.00000         1.0002010000
1.000000        1.0000201000
1.0000000       1.00000200910
1.00000000      1.0000002010
1.000000000     1.0000000201
1.0000000000    1.0000000020
1.00000000000   1.0000000002
1.000000000000  1.0000000000
    
Post 03 Jan 2008, 17:41
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 03 Jan 2008, 19:19
i have finished pretty good working atof, with lot of settings, and VERY good precision (because it doesn't use FPU - that also removes lot of problems).

It will be in FASMLIB 0.9.0, or I can post it in advance, if someone's interested...
Post 03 Jan 2008, 19:19
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 08 Jan 2008, 15:55
I'm interested. Smile
I'm always looking for a good itoa, atoi, ftoa or atof.
Post 08 Jan 2008, 15:55
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 08 Jan 2008, 16:12
this one is very precise, and thus also very slow Wink

here is ugly copy-pastery of functions involved:
Code:
;; @name conv._qfp_add
;; @desc
;;    This is internal procedure - do not call it directly.
;;    Adds two quad-precision floating point numbers.
;; @arg dest
;;    Pointer to buffer for destination number.
;;    Can be any of qfpnum1, qfpnum2.
;; @arg qfpnum1
;;    Pointer to first quad precision floating point number.
;; @arg qfpnum2
;;    Pointer to second quad precision floating point number.
;; @ret
;;    CF set on error, otherwise
;;    EAX = dest
;; @err ERR_OUT_OF_RANGE
;;    Resulting number is too large (above or equal binary 1e2147483648)
;; @err ERR_INTERNAL
;;    Bug in FASMLIB. Please report.
;; @note Quad-precision floating point number consists of 96bit mantissa
;;       (3 dwords, low order dword first). Follows 32bit (dword) signed exponent,
;;       that holds position of low order bit of mantissa.
;;       There is no sign. Number doesn't need to be normalized.
proc conv._qfp_add dest, qfpnum1, qfpnum2
local temp rd 4
     push    ebx ecx edx esi edi

     ;esi = qfpnum1, edx = qfpnum2
       mov     esi, [qfpnum1]
      mov     edx, [qfpnum2]

  ;EDI = temp
 lea     edi, [temp]

     ;ebx = position of highest bit in qfpnum1
   mov     ecx, 2*32
   bsr     eax, dword [esi+8]
  jnz     @f
  sub     ecx, 32
     bsr     eax, dword [esi+4]
  jnz     @f
  sub     ecx, 32
     bsr     eax, dword [esi]
    jz      .qfp1_zero
  @@:
     add     eax, ecx
    add     eax, dword [esi+12]
 mov     ebx, eax

        ;EAX = position of highest bit in qfpnum2
   mov     ecx, 2*32
   bsr     eax, dword [edx+8]
  jnz     @f
  sub     ecx, 32
     bsr     eax, dword [edx+4]
  jnz     @f
  sub     ecx, 32
     bsr     eax, dword [edx]
    jz      .qfp2_zero
  @@:
     add     eax, ecx
    add     eax, dword [edx+12]

     ;EBX position of highest bit total
  cmp     eax, ebx
    jbe     @f
  mov     ebx, eax
    @@:

 ;set destination mantissa to zero
   mov     dword [edi], 0
      mov     dword [edi+4], 0
    mov     dword [edi+8], 0

        ;ECX = destination exponent = highbit - 3*32 + 1
    lea     ecx, [ebx - 3*32 + 1]
       mov     dword [edi + 12], ecx

   ;add first dword of mantissa
        libcall conv._qfp_dword, esi, ecx
   mov     dword [edi], eax
    libcall conv._qfp_dword, edx, ecx
   add     dword [edi], eax
    adc     dword [edi+4], 0
    add     ecx, 32

 ;add second dword of mantissa
       libcall conv._qfp_dword, esi, ecx
   add     dword [edi+4], eax
  libcall conv._qfp_dword, edx, ecx
   add     dword [edi+4], eax
  adc     dword [edi+8], 0
    add     ecx, 32

 ;add third dword of mantissa
        libcall conv._qfp_dword, esi, ecx
   add     dword [edi+8], eax
  libcall conv._qfp_dword, edx, ecx
   add     dword [edi+8], eax

      ;if we don't need to add another bit, we're done
  jnc     .done

   ;insert top bit
     rcr     dword [edi+8], 1
    rcr     dword [edi+4], 1
    rcr     dword [edi], 1
      add     dword [edi+12], 1
   jo      .error_overflow

 jmp     .done

   ;QFP2 is zero, return QFP1
.qfp2_zero:
       mov     edi, esi
    jmp     .done

   ;QFP1 is zero, return QFP2
.qfp1_zero:
       mov     edi, edx
    jmp     .done

.done:
     ;copy result from temp (pointed by EDI) to dest
     mov     esi, [dest]
 mov     eax, [edi]
  mov     [esi], eax
  mov     eax, [edi+4]
        mov     [esi+4], eax
        mov     eax, [edi+8]
        mov     [esi+8], eax
        mov     eax, [edi+12]
       mov     [esi+12], eax

   ;return dest
        mov     eax, esi

.rnc:       clc
.r:  pop     edi esi edx ecx ebx
 ret
.rc: stc
 jmp     .r

.error_overflow:
      mov     eax, ERR_OUT_OF_RANGE
       jmp     .rc

.error_internal:
     mov     eax, ERR_FASMLIB
    jmp     .rc

endp    


Code:
;; @name conv._qfp_div
;; @desc
;;    This is internal procedure - do not call it directly.
;;    Divides quad-precision floating point number by dword.
;; @arg dest
;;    Pointer to buffer for destination number.
;;    Can be same as divident
;; @arg divident
;;    Pointer to quad precision floating point number which we divide.
;;    Can be same as dest.
;; @arg divisor
;;    Unsigned dword by which we divide.
;; @ret
;;    CF set on error, otherwise
;;    EAX = dest
;; @err ERR_OUT_OF_RANGE
;;    Resulting number is too small (below binary 1e-(2147483648 - 95))
;;    When number approaches minimal exponent, FASMLIB rather returns error than reducing
;;    precision by using fewer bits of mantissa.
;; @err ERR_INTERNAL
;;    Bug in FASMLIB. Please report.
;; @note Quad-precision floating point number consists of 96bit mantissa
;;       (3 dwords, low order dword first). Follows 32bit (dword) signed exponent,
;;       that holds position of low order bit of mantissa.
;;       There is no sign. Number doesn't need to be normalized.
proc conv._qfp_div dest, divident, divisor
        push    ebx ecx edx esi edi
 pushf

   ;EDI = dest
 mov     edi, [dest]

     ;copy divident to dest (if they aren't same)
       mov     esi, [divident]
     cmp     esi, edi
    je      @f
  cld
 movsd
       movsd
       movsd
       movsd
       @@:

 ;done if dest mantissa=0
    cmp     dword [edi], 0
      jne     taken @f
    cmp     dword [edi+4], 0
    jne     taken @f
    cmp     dword [edi+8], 0
    jne     taken @f
    mov     dword [edi+12], 0  ;reset exponent to 0 if mantissa is 0
    jmp     .done
       @@:

 ;EBX = divisor
      mov     ebx, [divisor]

  ;divide mantissa
    xor     edx, edx
    mov     eax, dword [edi+8]
  div     ebx
 mov     dword [edi+8], eax
  mov     eax, dword [edi+4]
  div     ebx
 mov     dword [edi+4], eax
  mov     eax, dword [edi]
    div     ebx
 mov     dword [edi], eax


    ;shift in more bits from result, as long as there is place at top of number (eg. upper bit is 0)
.another_dword:

 ;if remainder is 0, we are done, there are no more set bits in result
       test    edx, edx
    jz      .done

   ;EAX = get another dword of result
  xor     eax, eax
    div     ebx

     ;insert bits from resulting dword into dest
 mov     ecx, 32
.another_bit:

    ;if this is last dword of result(EDX=0) and all set bits of this dword are done (EAX=0), then stop
  test    edx, edx
    jz      .done
       test    eax, eax
    jnz     taken @f
    @@:

 ;if high order bit is 1, we can't insert any more bits
     bt      dword [edi+8], 31
   jc      untaken .done

   ;adjust exponent
    dec     dword [edi+12]
      jo      untaken .error_underflow        ;error if we can't get result with enough precision

    ;shift upper bit from EAX into mantissa
     shl     eax, 1                  ;get high bit of EAX to CF
  rcl     dword [edi], 1          ;and shift it into number
   rcl     dword [edi+4], 1
    rcl     dword [edi+8], 1
    jc      untaken .error_internal

 ;continue with next bit
     dec     ecx
 jnz     taken .another_bit

      ;continue with next dword
   jmp     .another_dword

.done:        mov     eax, edi
.rnc:   clc
.r:  popf
        pop     edi esi edx ecx ebx
 ret
.rc: stc
 jmp     .r

.error_underflow:
     mov     eax, ERR_OUT_OF_RANGE
       jmp     .rc

.error_internal:
     mov     eax, ERR_FASMLIB
    jmp     .rc

endp    


Code:
;routine to extract dword at given bit position in qfp
proc conv._qfp_dword qfpnum, index
  push    esi ecx ebx

     mov     esi, [qfpnum]
       mov     ecx, [index]
        sub     ecx, dword [esi+12]

     ;check which dwords we need
 cmp     ecx, 96
     jge     .outside
    cmp     ecx, 64
     jge     .in2
        cmp     ecx, 32
     jge     .in1
        cmp     ecx, 0
      jge     .in0
        cmp     ecx, -31
    jl      .outside

.low:       xor     eax, eax
    mov     ebx, dword [esi]
    add     ecx, 32
     shrd    eax, ebx, cl
        jmp     .r

.in0:     mov     eax, dword [esi]
    mov     ebx, dword [esi+4]
  shrd    eax, ebx, cl
        jmp     .r

.in1:     sub     ecx, 32
     mov     eax, dword [esi+4]
  mov     ebx, dword [esi+8]
  shrd    eax, ebx, cl
        jmp     .r

.in2:     sub     ecx, 64
     mov     eax, dword [esi+8]
  shr     eax, cl
     jmp     .r

.outside:
     xor     eax, eax

.r: pop     ebx ecx esi
 ret
endp    


Code:
;; @name conv._qfp_mul
;; @desc
;;    This is internal procedure - do not call it directly.
;;    Multiplies quad-precision floating point number by dword.
;; @arg dest
;;    Pointer to buffer for destination number.
;;    Can be same as qfpnum
;; @arg qfpnum
;;    Pointer to quad precision floating point number which we multiply
;;    Can be same as dest.
;; @arg multiplier
;;    Unsigned dword by which we multiply.
;; @ret
;;    CF set on error, otherwise
;;    EAX = dest
;; @err ERR_OUT_OF_RANGE
;;    Resulting number is too large (above or equal binary 1e2147483648)
;; @err ERR_INTERNAL
;;    Bug in FASMLIB. Please report.
;; @note Quad-precision floating point number consists of 96bit mantissa
;;       (3 dwords, low order dword first). Follows 32bit (dword) signed exponent,
;;       that holds position of low order bit of mantissa.
;;       There is no sign. Number doesn't need to be normalized.
proc conv._qfp_mul dest, qfpnum, multiplier
      push    ebx ecx edx esi edi

     ;EDI = dest
 mov     edi, [dest]

     ;ESI = qfpnum
       mov     esi, [qfpnum]

   ;EBX = multiplier
   mov     ebx, [multiplier]

       ;copy exponent
      mov     eax, dword [esi+12]
 mov     dword [edi+12], eax

     ;multiply mantissa
  mov     eax, dword [esi]
    mul     ebx
 mov     dword [edi], eax
    mov     eax, dword [esi+4]
  mov     ecx, edx
    mul     ebx
 add     eax, ecx
    mov     dword [edi+4], eax
  mov     ecx, edx
    mov     eax, dword [esi+8]
  mul     ebx
 add     eax, ecx
    mov     dword [edi+8], eax

      ;if we have some more bits, then shift them to mantissa
     mov     eax, edx
.insert_bit:

    ;no more bits?
      test    eax, eax
    jz      .done

   ;shift bit into result
      shr     eax, 1
      rcr     dword [edi+8], 1
    rcr     dword [edi+4], 1
    rcr     dword [edi], 1

  ;adjust exponent
    inc     dword [edi+12]
      jo      untaken .error_overflow

 ;follow with next bit
       jmp     .insert_bit

.done:   mov     eax, edi
.rnc:   clc
.r:  pop     edi esi edx ecx ebx
 ret
.rc: stc
 jmp     .r

.error_overflow:
      mov     eax, ERR_OUT_OF_RANGE
       jmp     .rc

endp    


Code:
;; @name conv._qfp2t
;; @desc
;;    This is internal procedure - do not call it directly.
;;    Converts quad-precision floating point format to non-normalized
;;    tenbyte (80-bit) floating point format, used natively by FPU.
;; @arg dest
;;    Pointer to 10 byte buffer for destination number.
;; @arg qfpnum
;;    Pointer to quad precision floating point number which we convert
;; @arg sign
;;    Sign of destination number (our QFP don't have sign)
;; @ret
;;    CF set on error, otherwise
;;    EAX = dest
;; @err ERR_OUT_OF_RANGE
;;    Resulting number is too large to be converted to tenbyte number
;;    (absolute above 1e16384 or under 1e-16383)
;; @err ERR_INTERNAL
;;    Bug in FASMLIB. Please report.
;; @note Quad-precision floating point number consists of 96bit mantissa
;;       (3 dwords, low order dword first). Follows 32bit (dword) signed exponent,
;;       that holds position of low order bit of mantissa.
;;       There is no sign. Number doesn't need to be normalized.
proc conv._qfp2t dest, qfpnum, sign
 push    ebx ecx edx esi edi

     ;EDI = dest
 mov     edi, [dest]

     ;ESI = qfpnum
       mov     esi, [qfpnum]

   ;ebx = position of highest bit in qfpnum1
   mov     ecx, 2*32
   bsr     eax, dword [esi+8]
  jnz     @f
  sub     ecx, 32
     bsr     eax, dword [esi+4]
  jnz     @f
  sub     ecx, 32
     bsr     eax, dword [esi]
    jz      .qfp_zero
   @@:
     add     eax, ecx
    add     eax, dword [esi+12]
 mov     ebx, eax

        ;save mantissa
      lea     eax, [ebx-31]
       libcall conv._qfp_dword, esi, eax
   mov     dword [edi+4], eax
  lea     eax, [ebx-63]
       libcall conv._qfp_dword, esi, eax
   mov     dword [edi], eax

        ;get exponent
       mov     eax, ebx
    add     eax, 16383
  cmp     eax, 32767
  ja      .error_overflow

 ;set sign in exponent
       cmp     [sign], 0
   je      @f
  bts     eax, 15
     @@:

 ;save sign+exponent
 mov     word [edi+8], ax
    jmp     .done

   ;special case: number is zero
.qfp_zero:
 mov     dword [edi], 0
      mov     dword [edi+4], 0
    mov     word [edi+8], 0
     jmp     .done

.done: mov     eax, edi
.rnc:   clc
.r:  pop     edi esi edx ecx ebx
 ret
.rc: stc
 jmp     .r

.error_overflow:
      mov     eax, ERR_OUT_OF_RANGE
       jmp     .rc

endp    


This is the actual routine. You can change the values in 10^e computing to increase speed od routine and decrease accurancy a bit. currently they are all "1", eg. max. accurancy.
Code:
;; @name extconv.fp_t
;; @desc
;;     Convert floating point from decimal ASCII string representation to
;;     FPU double-extended (80bit) floating point number, and returns it in ST0.
;; @ret
;;     CF set on error, otherwise
;;     ST0 = floating point number
;; @arg string
;;    Pointer to string containing floating point number.
;; @arg buflen
;;    Size of string's buffer.
;;    You can set this to -1 (FFFFFFFFh) if string is quaranteed to be properly zero-terminated.
;; @arg allowsign
;;    Sign allowance mode: 0 = no sign accepted, 1 = minus only accepted, 2 = minus and plus accepted.
;; @arg allowexp
;;    If 1, exponent is allowed.
;; @err ERR_NOT_FLOAT
;;    Number is not proper floating point number.
;; @err ERR_INVALID_MODE
;;    allowsign > 2, or allowexp > 1.
;; @err ERR_ZERO_SIZE
;;    buflen=0.
;; @warn
;;     FPU must be initialized and there must be place on FPU stack. This procedure operates same
;;     as FLD instruction.
;; @note
;;     If allowexp=0, then "e" character (like any other) immediately behind number simply stops conversion,
;;     number is converted with exponent 0, and no error is returned.
;; @note
;;     This function doesn't use FPU by itself (only to load result to ST0), and internal
;;     computations are done with very precision (96-bit mantissa, 32-bit exponent), so result
;;     should usually be very precise.
;; @nodep conv._qfp_add
;; @nodep conv._qfp_mul
;; @nodep conv._qfp_div
;; @nodep conv._qfp2t
proc extconv.fp_t string, buflen, allowsign, allowexp
locals
  bn   rd 4
  temp rd 4
  dest rd 4
  firstdigit dd ?
  lastdigit  dd ?
  exp      dd ?  ;exponent adjustment for mantissa digits behind dot
  sign             dd ?  ;sign: 0 is +, 1 is -
  dot        dd ?  ;dot flag: if 1, dot was already scanned
  tbnum      rd 3  ;ten-byte number
endl

  push    esi

     ;error is buflen=0
  cmp     [buflen], 0
 je      .error_zero_size

        ;check allowances
   cmp     [allowsign], 2
      ja      .error_mode
 cmp     [allowexp], 1
       ja      .error_mode

     ;ESI = string
       mov     esi, [string]

   mov     [exp], 0
    mov     [dot], 0
    mov     [sign], 0

       ;--------------------------------------------------
 ;scan number

    lodsb

   ;check plus
 cmp     [allowsign], 2
      jne     @f
  cmp     al, '+'
   jne     @f
  lodsb
       jmp     .sign_done
  @@:

 ;check minus
        cmp     [allowsign], 0
      je      @f
  cmp     al, '-'
   jne     @f
  mov     [sign], 1
   lodsb
       @@:

.sign_done:

  mov     [firstdigit], esi
   dec     [firstdigit]       ;we are behind first char now

        ; check first digit
 cmp     al, '0'
   jb      .error_bad_float
    cmp     al, '9'
   ja      .error_bad_float

        ;now scan digits
    jmp     .scan_mantissa_start
.scan_mantissa:
 lodsb
.scan_mantissa_start:
  cmp     al, '.'
   je      .scan_dot
   cmp     al, 'e'
   je      .scan_exponent
      cmp     al, '0'
   jb      .end_scan
   cmp     al, '9'
   ja      .end_scan

       ;it is digit - if we are behind dot, than adjust exponent
   cmp     [dot], 0
    je      .scan_mantissa
      dec     [exp]
       jmp     .scan_mantissa

.scan_dot:
        cmp     [dot], 0                   ;was dot already found?
  jne     .error_bad_float
    mov     [dot], 1
    jmp     .scan_mantissa

.end_scan:
        lea     eax, [esi-2]               ;we are now BEHIND last character, which is not part of mantissa
 mov     [lastdigit], eax
    jmp     .scan_done

.scan_exponent:

   ;save address of last digit
 lea     eax, [esi-2]
        mov     [lastdigit], eax

        ;if exponent is disallowed, then 'e' character ends scanning
      cmp     [allowexp], 0
       jne     @f
  jmp     .scan_done
  @@:

 ;get exponent
       push    ebx             ;eax = buflen - (esi - string) = remaining size of buffer
   mov     ebx, esi
    sub     ebx, [string]
       mov     eax, [buflen]
       sub     eax, ebx
    pop     ebx
 libcall conv.dec_id, esi, eax
       jc      .error_exponent
     add     [exp], eax

.scan_done:

       ;--------------------------------------------------
 ; calculate 10^exp

      ;initialize our floating point bignum
       mov     dword [bn], 1      ;mantissa=1
      mov     dword [bn+4], 0
     mov     dword [bn+8], 0
     mov     dword [bn+12], 0   ;exponent=0

  ;check exponent
     cmp     [exp], 0
    jg      .positive_exponent
  je      .exponent_done

  ;exponent is negative
       neg     [exp]
       jmp     .negative_exponent

      ;loop to calculate bn = 10^exp
.positive_exponent:

       ;eax = tentable[min(exp,9) - 1]
     mov      eax, [exp]
 cmp      eax, 0
     je       .exponent_done
     cmp      eax, 1
     jbe      @f
 mov      eax, 1
     @@:
     sub      [exp], eax
 dec      eax
        mov      eax, [conv.tentable + 4*eax]

   ;multiply bn with eax
       libcall  conv._qfp_mul, addr bn, addr bn, eax
       jc       .rc

    jmp      .positive_exponent

.negative_exponent:

      ;eax = tentable[min(eax,9) - 1]
     mov      eax, [exp]
 cmp      eax, 0
     je       .exponent_done
     cmp      eax, 1
     jbe      @f
 mov      eax, 1
     @@:
     sub      [exp], eax
 dec      eax
        mov      eax, [conv.tentable + 4*eax]

   ;multiply bn with eax
       libcall  conv._qfp_div, addr bn, addr bn, eax
       jc       .rc

    jmp      .negative_exponent

.exponent_done:

  ;--------------------------------------------------
 ; fun part - cycle through mantissa to calculate final value

    mov     [temp], 0
   mov     [temp+4], 0
 mov     [temp+8], 0
 mov     [temp+12], 0
        mov     [dest], 0
   mov     [dest+4], 0
 mov     [dest+8], 0
 mov     [dest+12], 0

    ; ESI = last digit of mantissa
      mov     esi, [lastdigit]
    jmp     .first_digit
.another_digit:

     ;end loop?
  dec     esi
 cmp     esi, [firstdigit]
   jb      .parse_done

.first_digit:
        mov     al, [esi]

       ;skip dot
   cmp     al, '.'
   je      .another_digit

  ;calculate digit*bn
 sub     al, '0'
   movzx   eax, al
     libcall conv._qfp_mul, addr temp, addr bn, eax
      jc      .rc

     ;add digit*bn to result
     libcall conv._qfp_add, addr dest, addr dest, addr temp
      jc      .rc

     ;multiply bn by 10
  libcall conv._qfp_mul, addr bn, addr bn, 10
 jc      .rc

     ;continue loop
      jmp     .another_digit

.parse_done:

  ;--------------------------------------------------
 ; now convert qfp to tenbyte floating point number

      libcall conv._qfp2t, addr tbnum, addr dest, [sign]
  jc      .rc

     fld     tbyte [tbnum]

.rnc:  clc
 cld
.r:  pop     esi
 ret
.rc: stc
 jmp     .r

.error_exponent:
      ;translate ERR_NOT_DECIMAL to ERR_NOT_FLOAT
 cmp     eax, ERR_NOT_DECIMAL
        je      .error_bad_float

        jmp     .rc

.error_mode:
 mov     eax, ERR_INVALID_MODE
       jmp     .rc

.error_bad_float:
    mov     eax, ERR_NOT_FLOAT
  jmp     .rc

.error_zero_size:
    mov     eax, ERR_ZERO_SIZE
  jmp     .rc
endp

idata {
  if used conv.tentable | INCLUDE_ALL_DATA eq 1
    conv.tentable dd 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
  end if
}    
Post 08 Jan 2008, 16:12
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 11 Jan 2008, 04:27
Excellent. Smile

Thank you very much.
Post 11 Jan 2008, 04:27
View user's profile Send private message Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 03 Feb 2008, 02:46
Are there any examples around of doing conversions with unicode?

I'm in the middle of converting everything over to unicode and the only thing left that I'm really having trouble with is the conversion of integers to characters.

The ITOA function posted on the previous page by Reverend doesn't work with unicode.
Post 03 Feb 2008, 02:46
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 03 Feb 2008, 03:26
i was thinking about unicode support, but it's low priority now.

ascii to unicode (eg. if all characters are below 128) is very easy, otherwise things become more complicated.
Post 03 Feb 2008, 03:26
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 03 Feb 2008, 05:09
It's just for integer to unicode. (I think)

I'm writing to an .ini file and I convert the integer to unicode and write it out with WritePrivateProfileStringW. This works fine for the regular strings, but I can't seem to convert the integer to the unicode equivalent.

I'm also converting a floating point to be displayed on a text label, which depends on converting integers. This doesn't seem to work, though.
Post 03 Feb 2008, 05:09
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 03 Feb 2008, 13:32
integer to UTF16 unicode is same as integer to ascii, just instead of byte ascii character, save it as word (eg. upper byte is zero).

or, you can convert to ascii, and then convert resulting string to unicode, by inserting zero byte after every byte of string.
Post 03 Feb 2008, 13:32
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 03 Feb 2008, 17:48
It makes sense, unfortunately I think that's beyond me with using someone else's conversion procedures.

I do need to convert from unicode to integer/ascii to float and back to unicode.

Basically, the user types in some numbers, with a period possibly, and then they press a convert button, it reads in that input, does the calculations, and outputs it.

I can post the full source if it will help out. I've just really been getting in asm lately and my knowledge of it is fairly lacking.
Post 03 Feb 2008, 17:48
View user's profile Send private message Reply with quote
Dopefish



Joined: 18 Nov 2007
Posts: 10
Dopefish 03 Feb 2008, 18:04
Alright, here's the source for the previous version (without unicode support) and the new one I'm working on that is supposed to have unicode support in the end.

The code is terrible, I'm sure. Smile

Any help, pointers, tips, etc. is always more than welcome.

Thanks.


Edit:
Another thing I just noticed is that depending on the height of the title bar, the content is shifted down. I've attached two images to show what I mean.


Description:
Filesize: 8.16 KB
Viewed: 19168 Time(s)

largetitlebar.png


Description:
Filesize: 7.29 KB
Viewed: 19169 Time(s)

smalltitlebar.png


Description:
Download
Filename: fovCalculator.zip
Filesize: 30.22 KB
Downloaded: 584 Time(s)

Post 03 Feb 2008, 18:04
View user's profile Send private message Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 05 Feb 2008, 11:18
These kind of tools are so narrow that they're probably useless. It has a GUI which takes some input, some output and an answer.

These kind of tools become better when they have multiple algorithms inside. Maybe some other graphics related stuff. Then if you are dealing with a graphics-related problem you can take this tool ***Calculator ***-meaning whatever (not only fov) and have it run in the background.

Otherwise - nicely done!
Post 05 Feb 2008, 11:18
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4, 5  Next

< 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.