News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Converting real8 to string

Started by RuiLoureiro, April 30, 2013, 04:07:27 AM

Previous topic - Next topic

jj2007

Quote from: dedndave on May 01, 2013, 08:24:31 AM
this is one of the finer points where Jochen and i disagree
the last digit does not to be correct to be considered "usable"

When I made my engineer, teachers told us to cut off at the last correct digit. I doubt that has changed... ;)

RuiLoureiro

Hi ToutEnMasm

Quote
The address passed to the function must be STRFLOAT.strf and not STRFLOAT
Not very usable
Sorry, but it is very usable for all.
       
        You have the complete code, so you can remove the length HERE:
Quote
            @@:     EXPONENTREAL_8W
                           
        _finish:    mov      eax, edi               
                       mov      edi, pRcl
                       sub      eax, edi

        _exit0:     ;mov      dword ptr [edi-4], eax    ; <--- HERE
                    mov      byte ptr [edi+eax], 0

So you have the solution to use it as you want

Quote
It's the first time i see something working like that:
12 00 00 00 20 33 2e 31-34 31 35 39 32 36 35 33
conclusion: it's the first time you look at my code.
         my library is full of this and i dont use things
         like this: STRFLOAT STRUCT (e.g. structures).
         I use EQU to do all my structures and i define
         data byte by byte in the data section. Well i
         use only my own library and not more.

To give you another example, a table of 20 pointers is this

                 dd 20         ; if we define this for unknown number of pointers
                 dd 0          ; <- no pointers in the table
_TblPtrX    dd 20 dup (?)

When i want to use it, i do something like this:

                mov     ecx, [_TblPtrX-4]
                jmp     _start
    _loop:
                mov     ebx, [_TblPtrX+ecx*4]   ; <-- ebx=pointer
                ;
                ; do something
                ;
    _start: sub     ecx, 1
                jns     short _loop
               
(note: the procs in my library follow this logic)

i think a macro may be used to define the buffer:

.data
             dd ?
label  X dup (?)


RuiLoureiro

Quote from: jj2007 on May 01, 2013, 06:25:33 PM
Quote from: dedndave on May 01, 2013, 08:24:31 AM
this is one of the finer points where Jochen and i disagree
the last digit does not to be correct to be considered "usable"

When I made my engineer, teachers told us to cut off at the last correct digit. I doubt that has changed... ;)
Yes Jochen, if we have operands with x significant digits and
               we do some set of operations, after that we lost significant digits
               at the end and there is no solution to that. They are lost.
               But in this case, the procedure that rounds it to 1 makes a little error
               and we should know this and cut it. I dont see another solution.
               If we use 2x significant digits, at the end, probably we have x
               significant digits correct, depends on the operations, but x we should
               have (probably they wasnt rounded).

dedndave

during a series of operations, you should retain as much precision as possible
while it's true that round-off errors accumulate, you are only making things worse if you continually throw away digits
when the final result is met, then you can round to some precision that is meaningful

in the real world, 6 or 7 digits is more than enough for most applications
the difference between 1.000001 and 1.000002 feet is very, very small and difficult to measure

there are cases where several more digits are useful
in electronics, i find these cases often in quantifying time or frequency, for example

jj2007

As Dave rightly writes, it's a "finer point". For an engineer, 1.2347 implies "the number is in the range 1.234650 to 1.23474999". From a viewpoint of numbers theory, and that's Dave's strong point, "usability" has a completely different meaning, so I consider his view legitimate but, of course, we agree to disagree :icon_mrgreen:

RuiLoureiro

#20
Quote
you are only making things worse if you continually throw away digits
generaly, any calculator uses the same number of digits for all
          operations, it doest use 10 digits for one operation and 8 for the
          next

Quote
you can round to some precision that is meaningful
yes, meanningful is the question

Quote
For an engineer, 1.2347 implies "the number is in the range 1.234650 to 1.23474999"
Or for an error limit of 0.0001 that 1.2347 could be X, for instance,
          with 5 decimal places
         
                                 1.23465 < X < 1.23475

Well, the problem of that PI is only a problem of showing it in real8 because
FPU uses it and works in real10 and the value is the same.

dedndave

something important to understand is that the value of Pi is known to many digits
the FPU gives you the REAL4, REAL8, or REAL10 value that it is capable of representing that is closest to Pi

when you evaluate that real number, don't expect to get digits that all match the value of Pi
the task of the routine is to evaluate the floating point value, as it is represented in the current format

RuiLoureiro

#22
About what we show with real8 format
-------------------------------------------------

    1. All numbers inside FPU are in real10 format.
       We cannot load or operate in real4 or real8.
       If we do that, first the real4 or real8 is
       converted to real10 inside FPU. If we move
        it to memory, there is a conversion to real4
        or real8 format.
       As far as i know.

     EDIT: we may use real4 or real8 mode but it is useless.

    2. When some procedure converts a real8 to
       string and show it, what we see may be
       the result of that procedure and not
       the number itself inside FPU. Dont
       forget that we need to do some operations
         to get the number
and the string.

       For instance, the real8 uses 52 bits+1
       implied. So we should have only 16 digits.
       Now see what happen when a procedure try
       17 digits:

Quote
000_00000_00000001 = 4.940656458412465 e-324
000_FFFFF_FFFFFFFF = 2.2250738585072009e-308
7FF_00000_00000000 =+INFINITY
FFF_00000_00000000 =-INFINITY
7FE_FFFFF_FFFFFFFF = 1.7976931348623157e+308
001_00000_00000000 = 2.2250738585072014e-308
0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
0.1
0.2
0.2999999999999999
0.4
0.5
0.6
0.7
0.8
0.9
*** STOP - ConvertFloat8DF  end test digits ***
-1.1000000000000001
-11.1
-111.09999999999999
-1111.0999999999999
-11111.1
-111111.10000000001
-1111111.1000000001
-11111111.1
-111111111.09999999
-1111111111.0999999
-11111111111.1
-111111111111.10001
-1111111111111.1001
-11111111111111.1
-111111111111111.09
-1111111111111111.1
-1.1111111111111112e+16
-1.1111111111111111e+17
-2.2000000000000002
-22.199999999999999
-222.19999999999999
-2222.1999999999998
-22222.200000000001
-222222.20000000001
-2222222.2000000002
-22222222.199999999
-222222222.19999999
-2222222222.1999998
-22222222222.200001
-222222222222.20001
-2222222222222.2002
-22222222222222.199
-222222222222222.19
-2222222222222222.2
-2.2222222222222224e+16
-2.2222222222222222e+17
-3.3
-33.3
-333.3
-3333.3
-33333.3
-333333.3
-3333333.3
-33333333.3
-333333333.3
-3333333333.3
-33333333333.3
-333333333333.3
-3333333333333.3
-33333333333333.3
-333333333333333.3
-3333333333333334
-3.333333333333333e+16
-3.333333333333333e+17
*** STOP - ConvertFloat8DF ***

now, the same procedure using 16 digits
and all seems to be perfect

Quote
000_00000_00000001 = 4.94065645841247 e-324
000_FFFFF_FFFFFFFF = 2.225073858507201e-308
7FF_00000_00000000 =+INFINITY
FFF_00000_00000000 =-INFINITY
7FE_FFFFF_FFFFFFFF = 1.797693134862316e+308
001_00000_00000000 = 2.225073858507201e-308
0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
*** STOP - ConvertFloat8DF  end test digits ***
-1.1
-11.1
-111.1
-1111.1
-11111.1
-111111.1
-1111111.1
-11111111.1
-111111111.1
-1111111111.1
-11111111111.1
-111111111111.1
-1111111111111.1
-11111111111111.1
-111111111111111.1
-1.111111111111111e+15
-1.111111111111111e+16
-1.111111111111111e+17
-2.2
-22.2
-222.2
-2222.2
-22222.2
-222222.2
-2222222.2
-22222222.2
-222222222.2
-2222222222.2
-22222222222.2
-222222222222.2
-2222222222222.2
-22222222222222.2
-222222222222222.2
-2.222222222222222e+15
-2.222222222222223e+16
-2.222222222222222e+17
-3.3
-33.3
-333.3
-3333.3
-33333.3
-333333.3
-3333333.3
-33333333.3
-333333333.3
-3333333333.3
-33333333333.3
-333333333333.3
-3333333333333.3
-33333333333333.3
-333333333333333
-3.33333333333333e+15
-3.33333333333333e+16
-3.33333333333333e+17
*** STOP - ConvertFloat8DF ***

qWord

Quote from: RuiLoureiro on May 02, 2013, 02:26:37 AMWe cannot load or operate in real4 or real8.
yes, of course we can do that.

Quote from: RuiLoureiro on May 02, 2013, 02:26:37 AM
       If we do that, first the real4 or real8 is
       converted to real10 inside FPU.
which means to zero extend the fraction bits.
MREAL macros - when you need floating point arithmetic while assembling!

RuiLoureiro

Quote from: qWord on May 02, 2013, 02:39:02 AM
Quote from: RuiLoureiro on May 02, 2013, 02:26:37 AMWe cannot load or operate in real4 or real8.
yes, of course we can do that.
What are the instructions you use to do that
               and does not imply a conversion ?
               Do you know faddreal8 or something ?
               May be it operates in real8 but i dont know.
               For instance do you know how to load PI
               in real8 ? I know fldpi only and it is real10
               as far as i know.

qWord

simply set the precision control to 53 or 24 bit and use corresponding values and constants - loading REAL10 values is still possible, but the precision is lost after the first operation1 (due rounding to 53/24 bit).

1: +-*/sqrt()
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

The effect can be quite significant:

NameA equ high precision        ; assign a descriptive name here
TestA proc
  FpuSet MbNear64
  mov ebx, AlgoLoops-1        ; loop e.g. 100x
  align 4
  .Repeat
        fldpi
        fld1
        fdiv
        fld1
        fadd
        fldpi
        fmul        ; 13.011197054679151860
        fstp st
        dec ebx
  .Until Sign?
  ret
TestA endp
TestA_endp:

align 16
TestB_s:
NameB equ low precision        ; assign a descriptive name here
TestB proc
  FpuSet MbNear24
  mov ebx, AlgoLoops-1        ; loop e.g. 1000x
  align 4
  .Repeat
        fldpi
        fld1
        fdiv
        fld1
        fadd
        fldpi
        fmul        ; 13.011198043823242190
        fstp st
        dec ebx
  .Until Sign?
  ret
TestB endp
TestB_endp:

Windows, for example, sets precision to 53 bits, afaik with the argument "that's faster than full precision". At least on my trusty old Celeron, the sequence above takes 7.1 cycles for both 64 and 24 bits precision:

Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
loop overhead is approx. 2183/1000 cycles

7110    cycles for 1000 * high precision
7113    cycles for 1000 * low precision

7122    cycles for 1000 * high precision
7111    cycles for 1000 * low precision

TouEnMasm

The address passed to the function must be STRFLOAT.strf and not STRFLOAT
Not very usable
Quote
                Sorry, but it is very usable for all.

Too much difficult ?
Here is a standard api call
Quote
invoke  ConvertFloat8DSD,addr r8,addr strfloat,4 ;min 3 digits
Fa is a musical note to play with CL

qWord

Quote from: jj2007 on May 02, 2013, 03:55:21 AMAt least on my trusty old Celeron, the sequence above takes 7.1 cycles for both 64 and 24 bits precision
not surprisingly, because the operations use the full 64 bit and than round to 53/24 bit.
It might be more interesting to see the effect on transcendental and logarithmic function. Especially because the precision of these functions seems to be implementation specific: For example, Intel guarantees an error below 1 ulp only for Pentium processors or newer (transcendental functions).

EDIT: transcendental and logarithmic functions are not affected by the precision control.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on May 02, 2013, 04:21:57 AMnot surprisingly, because the operations use the full 64 bit and than round to 53/24 bit.

So the question is, why do Windows (and CRT, it seems) unnecessarily sacrifice precision, if full precision is not slower? To maintain compatibility, in the negative sense, with SSE-based libraries? ::)

I can't see any reasonable argument for not using the full 80/64 bit mode...