The MASM Forum

General => The Laboratory => Topic started by: Gunther on January 01, 2015, 02:38:57 PM

Title: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 01, 2015, 02:38:57 PM
To print out REAL10 values with an average accuracy of 19.2 significant decimal digits under Windows seems to be a real challenge. The Windows RTL (I think it's msvcrt.dll) doesn't support REAL10 values and maps long double to double. That gives a mess. We had a lot of discussions in the old and the new forum about this point. There are workarounds available and here is another one.

The attached archive r10.zip contains the sources and binaries for a small test program. Here is the output:
Quote
x = 3.1415926535897932385

Please, press enter to end the application ...
For re-compiling you'll need the MinGW, MSVC won't work. The reason is simple: The GNU libc (glibc) has the full support for REAL10 numbers. But as a factory default, the MinGW uses the procedures of MSVC for printf, scanf etc. However, MinGW also comes with a set of alternative implementations that do properly support long doubles. These must be linked in. How to call those procedures shows my little test program.

I would not say that this technique to call printf from assembly language is ideal. But I've no other way at the moment. On the other hand, my example prints out 20 significant decimal digits; the rounding in the last digit is okay. So far I have found no number where this technique fails (on average, 19 decimal digits are printed). But it may well be that there are such numbers.

My next idea was, to check printf from the glibc to collect some ideas. My goal is to write an appropriate assembly language procedure, which can be called from MSVC or assembly language. But that's not a simple task. The glibc manual (http://www.gnu.org/software/libc/manual/pdf/libc.pdf) has 1095 pages. The function printf itself is very short:

__printf (const char *format, ...)
{
   va_list arg;
   int done;

  va_start (arg, format);
  done = vfprintf (stdout, format, arg);
  va_end (arg);

  return done;
}

It uses varargs to get the arguments in a variable length argument list. The full code is here (https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf.c;h=4c8f3a2a0c38ab27a2eed4d2ff3b804980aa8f9f;hb=3321010338384ecdc6633a8b032bb0ed6aa9b19a). All the fancy format magic goes in vfprintf (https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/vfprintf.c;h=fc370e8cbc4e9652a2ed377b1c6f2324f15b1bf9;hb=3321010338384ecdc6633a8b032bb0ed6aa9b19a). It has over 2000 sophisticated lines of code.

I've to figure out now the REAL10 parts and what happens there. Any help is welcome. Testing results and comments are welcome, too.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 01, 2015, 09:05:45 PM
Interesting stuff, Gunther :t
The vfprintf source is C code, i.e. the step from C to assembly is not transparent. The music plays in the two functions marked in red below.
00405595        ³.ÚEB 22          jmp short 004055B9
00405597        ³> ³892C24         Úmov [local.42], ebp
0040559A        ³. ³C74424 08 0000 ³mov dword ptr [local.40], 0
004055A2        ³. ³C74424 04 0A00 ³mov dword ptr [local.41], 0A
004055AA        ³. ³E8 F1130000    ³call 004069A0
004055AF        ³. ³838424 8C00000 ³add dword ptr [local.7], 1
004055B7        ³. ³89C5           ³mov ebp, eax
004055B9        ³> À897C24 04      +mov [local.41], edi
004055BD        ³.  892C24         ³mov [local.42], ebp
004055C0        ³.  E8 BB0E0000    ³call 00406480
004055C5        ³.  83C0 30        ³add eax, 30
004055C8        ³.  8806           ³mov [esi], al
004055CA        ³.  83C6 01        ³add esi, 1
004055CD        ³.  3B9C24 8C00000 ³cmp ebx, [local.7]
004055D4        ³. 7F C1          Àjg short 00405597
004055D6        ³.  8B5C24 24      mov ebx, [local.33]
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: adeyblue on January 02, 2015, 02:34:16 AM
In the source, the float stuff is in __print_fp, and in there it pretty much just offloads to GNU MP, line 329 seems to be where the actual fun begins (https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf_fp.c;h=43c43c20390759df75731856d0068a606b3291ff;hb=1311b164df26ee49740b805d4f32fffde163b1e6).
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 02, 2015, 06:38:28 AM
Line 329 points to __mpn_extract_long_double (http://osxr.org/glibc/source/sysdeps/ieee754/ldbl-128/ldbl2mpn.c?v=glibc-2.17#0033):
QuoteConvert a `long double' in IEEE854 quad-precision format to a
0028    multi-precision integer representing the significand scaled up by its
0029    number of bits (113 for long double) and an integral power of two
0030    (MPN frexpl).

But still no assembly code there :(
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 02, 2015, 12:08:33 PM
Jochen,

Quote from: jj2007 on January 01, 2015, 09:05:45 PM
Interesting stuff, Gunther :t

I hope so.

Quote from: jj2007 on January 01, 2015, 09:05:45 PM
The vfprintf source is C code, i.e. the step from C to assembly is not transparent. The music plays in the two functions marked in red below.

There's good news on the way. Since gcc compiles in every language always via assembly (gas is the back end), the assembly language source is available in any case. That costs nothing, only one more compiler run with the switch -S. As an example I've included the assembly language source of r10.c. This is r10.s and it can be read with every editor (clean ASCII text). I think that's transparent enough. Of course, one has to pay a price. The assembly language source of the C code is in AT&T syntax. But that's no big deal, because I've enough experiences in reading and writing AT&T syntax. I won't go the way over a debugger, because:

adeyblue,

Quote from: adeyblue on January 02, 2015, 02:34:16 AM
In the source, the float stuff is in __print_fp, and in there it pretty much just offloads to GNU MP, line 329 seems to be where the actual fun begins (https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/printf_fp.c;h=43c43c20390759df75731856d0068a606b3291ff;hb=1311b164df26ee49740b805d4f32fffde163b1e6).

good catch.  :t It's probably sufficient to examine this procedure.  The author is Ulrich Drepper. He was over years the maintainer of the glibc. He is a complicated personality with a large ego. We know that well from our forum, too. But he writes good articles (http://www.akkadia.org/drepper/cpumemory.pdf) and sophisticated code. That is what counts.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: nidud on January 02, 2015, 10:47:51 PM
deleted
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 03, 2015, 12:04:34 AM
Quote from: nidud on January 02, 2015, 10:47:51 PM
and there seems to be a bug there in JWASM (invoke)

Indeed. Below the standard Masm32 version for testing.
Besides, printf apparently can't handle REAL10:
x = -88796093704934486000000000000000000000000000.0000000000000000000

include \masm32\include\masm32rt.inc

.data
format  db "x = %1.19Lf",10,0
num dt 3.14159265358979323846264338327

.code
start:
invoke crt_printf, addr format, num
xor eax, eax
ret
end start
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: nidud on January 03, 2015, 01:01:26 AM
deleted
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 03, 2015, 02:47:56 AM
Quote from: nidud on January 03, 2015, 01:01:26 AM
I haven't seen 'L' being used for LONG in a format string ?

Wellllll... that was you who proposed that format, right? ;-)
It seems it's a known problem (http://stackoverflow.com/questions/4089174/printf-and-long-double), good ol' Microsoft CRT simply doesn't know what a long double is. We also had a thread on printf and long integers (http://masm32.com/board/index.php?topic=2769.0) some time ago, but the solution proposed there (msvcrt100.dll) doesn't work with floats. Take MasmBasic Str$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1186) - 19 digits... ;-)
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: nidud on January 03, 2015, 03:29:43 AM
deleted
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 03, 2015, 04:34:23 AM
Hi nidud,

thank you for your answers.
Quote from: nidud on January 02, 2015, 10:47:51 PM
Gunther, I did some testing on printing long double
and there seems to be a bug there in JWASM (invoke)
...
the stack is destroyed here on return

that's real bad news. Will become jWasm more and more problematic? Since I'm not a friend of the fancy macro stuff (invoke etc.) I couldn't find that error. I think Sinsi has a similar point of view.

I've described the limitations of the MS RTL in my first post of this thread. We had a lot of discussions about it, for example here (http://www.masmforum.com/board/index.php?topic=14790.0) or here (http://masm32.com/board/index.php?topic=1768.msg17962#msg17962). So that's not new and the behavior of msvcrt.dll is also not new.

Quote from: jj2007 on January 03, 2015, 02:47:56 AM
Take MasmBasic Str$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1186) - 19 digits... ;-)

Except numbers that start with 923 (http://masm32.com/board/index.php?topic=94.msg41105#msg41105). For such numbers, one has to use glibc:
Quote
x = 923.6666666666666667

Please, press enter to end the application ...

That gives 19 numbers and the rounding in the last decimal digit is okay. The archive r10U1.zip is attached under this post.

A further step forward would be, for example, to write assembly language code for ml, jWasm, nasm, fasm or whatever assembler and using the GNU linker ld for building the EXE with the glibc library. I've at the moment a good discussion via PM with Vortex about this point. But the build process isn't easy. Here is the build dump:
Quote
c:\gcc\work>gcc -v -o r10.exe r10.o r10.obj
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/i686-w64-mingw32/4.8.0/lto-wrapp
er.exe
Target: i686-w64-mingw32
Configured with: ../../../src/gcc-trunk/configure --host=i686-w64-mingw32 --buil
d=i686-w64-mingw32 --target=i686-w64-mingw32 --prefix=/mingw32 --with-sysroot=/t
emp/x32-trunk-win32-sjlj/mingw32 --enable-shared --enable-static --enable-target
s=all --enable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-
time=yes --enable-threads=win32 --enable-libgomp --enable-lto --enable-graphite
--enable-checking=release --enable-fully-dynamic-string --enable-version-specifi
c-runtime-libs --enable-sjlj-exceptions --disable-isl-version-check --disable-cl
oog-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-bo
otstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror
--disable-symvers --with-gnu-as --with-gnu-ld --with-arch-32=i686 --with-arch-64
=nocona --with-tune-32=generic --with-tune-64=core2 --with-host-libstdcxx='-stat
ic -lstdc++' --with-libiconv --with-system-zlib --with-gmp=/temp/mingw-prereq/i6
86-w64-mingw32-static --with-mpfr=/temp/mingw-prereq/i686-w64-mingw32-static --w
ith-mpc=/temp/mingw-prereq/i686-w64-mingw32-static --with-isl=/temp/mingw-prereq
/i686-w64-mingw32-static --with-cloog=/temp/mingw-prereq/i686-w64-mingw32-static
--enable-cloog-backend=isl --with-pkgversion='rev, Built by MinGW-builds projec
t' --with-bugurl=http://sourceforge.net/projects/mingwbuilds/ CFLAGS='-O2 -pipe
-I/temp/x32-trunk-win32-sjlj/libs/include -I/temp/mingw-prereq/x32-zlib/include
-I/temp/mingw-prereq/i686-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -I/tem
p/x32-trunk-win32-sjlj/libs/include -I/temp/mingw-prereq/x32-zlib/include -I/tem
p/mingw-prereq/i686-w64-mingw32-static/include' CPPFLAGS= LDFLAGS='-pipe -L/temp
/x32-trunk-win32-sjlj/libs/lib -L/temp/mingw-prereq/x32-zlib/lib -L/temp/mingw-p
rereq/i686-w64-mingw32-static/lib -L/temp/x32-trunk-win32-sjlj/mingw32/opt/lib'
Thread model: win32
gcc version 4.8.0 20130314 (experimental) (rev, Built by MinGW-builds project)
COMPILER_PATH=c:/mingw/bin/../libexec/gcc/i686-w64-mingw32/4.8.0/;c:/mingw/bin/.
./libexec/gcc/;c:/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../../i686-w
64-mingw32/bin/
LIBRARY_PATH=c:/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/;c:/mingw/bin/../lib
/gcc/;c:/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../../i686-w64-mingw3
2/lib/../lib/;c:/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../../lib/;c:
/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../../i686-w64-mingw32/lib/;c
:/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../
COLLECT_GCC_OPTIONS='-v' '-o' 'r10.exe' '-mtune=generic' '-march=i686'
c:/mingw/bin/../libexec/gcc/i686-w64-mingw32/4.8.0/collect2.exe --sysroot=C:/gc
cbuild/msys/temp/x32-trunk-win32-sjlj/mingw32 -m i386pe -Bdynamic -o r10.exe c:/
mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../../i686-w64-mingw32/lib/../
lib/crt2.o c:/mingw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/crtbegin.o -Lc:/mingw/
bin/../lib/gcc/i686-w64-mingw32/4.8.0 -Lc:/mingw/bin/../lib/gcc -Lc:/mingw/bin/.
./lib/gcc/i686-w64-mingw32/4.8.0/../../../../i686-w64-mingw32/lib/../lib -Lc:/mi
ngw/bin/../lib/gcc/i686-w64-mingw32/4.8.0/../../../../lib -Lc:/mingw/bin/../lib/
gcc/i686-w64-mingw32/4.8.0/../../../../i686-w64-mingw32/lib -Lc:/mingw/bin/../li
b/gcc/i686-w64-mingw32/4.8.0/../../.. r10.o r10.obj -lmingw32 -lgcc -lgcc_eh -lm
oldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmi
ngw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt c:/mingw/bin/../lib/gcc/i686-
w64-mingw32/4.8.0/crtend.o
So, Erol is working on it, I've to work on my kernel-mode driver with an approaching dead line. It will take some time before we've results.

Without any doubts, that would be only another workaround, because that won't work with Microsoft's VS.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Vortex on January 03, 2015, 08:26:06 AM
Hi Gunther,

I guess I found the dependencies \ libraries involved to build the project. Tools used :

- Agner Fog's objconv tool to extract the members from libraries :

objconv -lx library.a

objconv was used also to disassemble the object modules to find the other dependencies. __mingw_vprintf was the first module but it looks like that there are a lot of member functions linked by ld.exe

- Nirsoft's SearchMyFiles to search the module names inside libraries.

http://www.nirsoft.net/utils/search_my_files.html

There are two builds. Real10ValA is using all the necessary object modules extracted from libraries.

A more simple version, Real10ValB is using the libraries but I was forced to specify pseudo-reloc.o in the command-line to avoid linkage error.

I used my tiny C run-time library adapted to MinGW. The size of r10.exe is reduced from 77537 bytes to 29184 bytes
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 03, 2015, 10:00:15 AM
Great job, Erol.  :t Thank you for the fast work. I'll try that tomorrow. It seems to me that we've another workaround.  :t

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 03, 2015, 10:18:37 AM
Erol,

I've tested both applications and both crashed, as well under Win7-64 as under WinXP. I think you're on the right way. It's probably a minor detail.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Vortex on January 03, 2015, 10:19:14 PM
Hi Gunther,

My apologies for the inconvenience. This time, I rebuilt the project using the parameters provided by the verbose report. You can check the image parameters.PNG to see the options copied to the batch file. The paths in the .bat file can be simplified.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 04, 2015, 02:17:36 AM
Erol,

never mind. The new version, included in Real10ValC.zip works fine. I'll check the code and build process in detail tomorrow, because I've to finish my kernel-mode driver. It works now as expected, but I've to write the documentation, which is a lot of work to do.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Vortex on January 04, 2015, 03:40:05 AM
Hi Gunther,

No any problem. The internals of MinGW are very complicated and probably the A and B examples are missing something important.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 04, 2015, 04:30:02 AM
Erol,

Quote from: Vortex on January 04, 2015, 03:40:05 AM
The internals of MinGW are very complicated and probably the A and B examples are missing something important.

that's my impression, too. But my idea should be practicable in both worlds (Win-32 and Win-64). By the way, what's the behavior of Pelle's C with long double values?

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 04, 2015, 04:51:24 AM
Quote from: Gunther on January 04, 2015, 04:30:02 AMwhat's the behavior of Pelle's C with long double values?

  long double ld=1234567890.1234567890;
  printf("This is a long double: %.9f\n", ld);

  This is a long double: 1234567890.123456746

@Erol: What about a dll or static lib version for the ordinary mortals among us?
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Vortex on January 04, 2015, 04:58:07 AM
Hi Jochen,

Quote@Erol: What about a dll or static lib version for the ordinary mortals among us?

As I mentioned above, the linking process managed by ld.exe is very complicated. We have to understand the relations between the MinGW libraries. For the moment, it's better to mimic some portions of the verbose logging. Not a perfect solution but it seems to work.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: adeyblue on January 05, 2015, 02:11:55 PM
Thanks to Vortex and Gunther diving the necessary command line, I've created some dlls for just the various __mingw_printf / scanf functions. It's pretty much just a matter of using a def to say what to export and adding in all those libraries to the linker. The f* versions aren't there, since the FILE struct is likely to be different for other compilers / versions of msvcrt, but you can just uncomment them from the def if you want them.

It seems to work from the quick test I gave it.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 06, 2015, 12:00:04 AM
Hi adeyblue,

thank you for your distribution. I'll test it this evening. Could one integrate it into VS?

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: adeyblue on January 06, 2015, 08:40:51 AM
As far as you can call the functions, yes. You can't print long doubles directly using the C/C++ compiler since they're really only normal 64-bit doubles, but you can print them if you get them via other means (like below where its defined in hex).

MASM should be fine though.


void PrintIt(const char* p, ...)
{
va_list a;
va_start(a, p);
int ret = __mingw_vprintf(p, a);
va_end(a);
}

void test()
{
unsigned doub[4]; // 1234567890.123456789 in hex
doub[3] = 0;
doub[2] = 0x401d;
doub[1] = 0x932C05A4;
doub[0] = 0x3F35BA6E;
__m128 val = _mm_loadu_ps((float*)&doub[0]);
__mingw_printf("Value is %.9Lf\n", val);
PrintIt("Value is %.9Lf\n", val);
}


I'm trying to build the relevant bits from source, but the resulting dll is crash happy.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 06, 2015, 11:45:44 AM
Hi adeyblue,

Quote from: adeyblue on January 06, 2015, 08:40:51 AM
I'm trying to build the relevant bits from source, but the resulting dll is crash happy.

yes, entire topic is complicated, but your plan could be successful.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 07, 2015, 07:49:39 AM
Quote from: adeyblue on January 06, 2015, 08:40:51 AMI'm trying to build the relevant bits from source, but the resulting dll is crash happy.

MS VC 2010 gave me "Cannot load the project due to a corrupt project file" (I've never seen a successful conversion, VS is such a crap :icon_redface:).

Can you build the DLL in 32-bit and post it here? I'd like to compare the results to my own code.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: GoneFishing on January 07, 2015, 08:30:47 AM
The .vcproj file contains absolute paths "f:\dev-cpp\lib32;f:\dev-cpp\lib32\gcc\4.7.2\" which may not exist on you computer.
I've just downloaded the archive and found both 32 abd 64 bit dlls in "files" folder.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 07, 2015, 08:46:16 AM
Hi vertograd,

Quote from: vertograd on January 07, 2015, 08:30:47 AM
The .vcproj file contains absolute paths "f:\dev-cpp\lib32;f:\dev-cpp\lib32\gcc\4.7.2\" which may not exist on you computer.
I've just downloaded the archive and found both 32 abd 64 bit dlls in "files" folder.

oh yes, these tricky project files. What about this: Writing a batch file and using the command line compiler? I hope that Microsoft provides it. That avoids the trouble.

Gunther
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: GoneFishing on January 07, 2015, 08:51:52 AM
Hi Gunther,
The command line for MS VS project can be terrific  :shock:
Once I started to write python script that parses .vcproj and converts it to  linux makefile (for opengl examples ) . The first part was done but the later is not yet finished .
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 07, 2015, 09:31:58 AM
Quote from: vertograd on January 07, 2015, 08:30:47 AMI've just downloaded the archive and found both 32 abd 64 bit dlls in "files" folder.

Oops, I was so busy trying to compile that I had not even looked into that folder. Thanks, adeyblue & vertograd :t

Here is a first test with the 32-bit DLL (left: MasmBasic Str$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1186), right: __mingw_sprintf). It seems that while you can specify more than 19 digits with sprintf(), their value is kind of doubtful:
digits    12345678901234567890    12345678901234567890
#1      0.1111111111111111111   0.1111111111111111111028290
#2      0.2222222222222222222   0.2222222222222222222056580
#3      0.3333333333333333333   0.3333333333333333333152633
#4      0.4444444444444444444   0.4444444444444444444113160
#5      0.5555555555555555555   0.5555555555555555555073688
#6      0.6666666666666666666   0.6666666666666666666305266
#7      0.7777777777777777777   0.7777777777777777777536844
#8      0.8888888888888888888   0.8888888888888888888768422
#9      1.000000000000000000    1.0000000000000000000000000
#10     1.111111111111111111    1.1111111111111111111231578
#11     1.222222222222222222    1.2222222222222222222463156

#86     9.555555555555555549    9.5555555555555555490021558
#87     9.666666666666666660    9.6666666666666666600168933
#88     9.777777777777777771    9.7777777777777777710316309
#89     9.888888888888888882    9.8888888888888888820463685
#90     9.999999999999999993    9.9999999999999999930611061
#91     10.11111111111111110    10.1111111111111111040758437
#92     10.22222222222222221    10.2222222222222222150905813
#93     10.33333333333333333    10.3333333333333333261053189
#94     10.44444444444444444    10.4444444444444444371200564
#95     10.55555555555555555    10.5555555555555555481347940
#96     10.66666666666666666    10.6666666666666666591495316
#97     10.77777777777777777    10.7777777777777777701642692
#98     10.88888888888888888    10.8888888888888888811790068
#99     10.99999999999999999    10.9999999999999999921937444
#100    11.11111111111111110    11.1111111111111111032084819

#996    110.6666666666666673    110.6666666666666673096708351
#997    110.7777777777777784    110.7777777777777784215529344
#998    110.8888888888888895    110.8888888888888895334350337
#999    111.0000000000000006    111.0000000000000006453171331
#1000   111.1111111111111118    111.1111111111111117571992324


Source:
include \masm32\MasmBasic\MasmBasic.inc      ; download (http://masm32.com/board/index.php?topic=94.0)
  SetGlobals MyR10:REAL10, Add01:REAL10=0.111111111111111111111, buffer[100]:BYTE
  Init
  Dll "\Masm32\bin\MingwPrintf32.dll"      ; adjust path if necessary
  Declare void __mingw_sprintf, C:?        ; ccall, vararg
  xor ecx, ecx
  Print "digits", Tb$, "  12345678901234567890", Tb$, "  12345678901234567890"
  .Repeat
      fld MyR10      ; load variable on FPU
      fld Add01      ; load modifier
      fadd           ; modify
      fstp MyR10     ; store back to memory
      .if ecx<11 || ecx>=85 && ecx<100 || ecx>=995
            __mingw_sprintf(addr buffer, "%1.25Lf", MyR10)
            Print Str$("\n#%i\t", ecx+1), Str$(MyR10), Tb$, addr buffer
      .elseif ecx==11 || ecx==100
            Print    ; insert a blank line
      .endif
      inc ecx
  .Until ecx>=1000
  Inkey CrLf$, "--- hit any key ---"
  Exit
end start


Source & exe attached, requires the latest MB version of 7 Jan.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: adeyblue on January 07, 2015, 09:55:29 AM
Yeah, you have to modify those absolute paths to point to your lib / lib\gcc\x.x.x\ directories if you want to create the dll. It was just about under the forum size limit without including the actual .o files (one which is 5MB by itself). The VC linker command line used is at the top of printf.c.

Anyhoo, I managed to compile it from source which has slightly minimized the size of the dll. I've attached what I ended up with. A static library and the dll are in the lib* directories. To build it GCC needs to be in your path, and you'll have to point the include and lib variables in source_code\build.cmd to point to your various MinGW include and lib dirs. It'll build 64 and 32-bit, optimized and debug versions of the code, provided you have the 64-bit MinGW and both sets of libs. I don't know what'll happen otherwise.

There's tons of warnings about -fpic not being necessary, primarily because I couldn't be bothered to figure out what it was needed for and what it wasn't. The static lib works with MinGW and VC2008 and above, it might not be compatible with any other CRT like Pelles due to the differences in FILE struct size. The dll should be usable by anything that can link to dlls.
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: jj2007 on January 07, 2015, 10:13:50 AM
@adeyblue: Works like a charm, see reply #28 (http://masm32.com/board/index.php?topic=3915.msg41394#msg41394) (with old and latest DLL alike) :t
Title: Re: Printing REAL10 values with the full range of decimal digits
Post by: Gunther on January 08, 2015, 02:22:35 AM
Hi adeyblue,

special thanks to you.  :t You've done a good job. I think a lot of our forum members are very grateful.

Gunther