News:

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

Printing long double with MASM32

Started by Gunther, September 08, 2010, 01:47:09 AM

Previous topic - Next topic

Gunther

I would like to try MASM32. It seems to be a good maintained and practicable project.

Is there a way to print long double or extended precision values? Hutch knows what I mean. For example, VS "don't" know long double. MinGW "know's" that type, can calculate with such values, but it uses the MS implementation of printf (based on MSVCRT). Printing such values produces garbage on the screen. PowerBASIC supports that data type and can print such values properly since version 3.0, I think.

I've to make some numerical experiments with my students and MASM32  would be a good solution for that problem.

Gunther
Forgive your enemies, but never forget their names.

raymond

You can do ANYTHING you want with assembly. There's NO limitation whatsoever.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

hutch--

Gunther,

If you mean 80 bit FP (REAL10) then I think from memory that Ray Filiatreault has a string conversion for it. If printf is the limitation on the data size I woud be inclined to convert it then display or print it in whatever way you want.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

If you don't actually need the additional precision, you can get around the garbage problem by using the FPU to convert the long double into a double.
eschew obfuscation

Gunther

Thank you guys for your fast answers.


Quote from: raymond September 08, 2010, at 04:10:08 AMYou can do ANYTHING you want with assembly. There's NO limitation whatsoever.

That's for sure.

Quote from: hutch-- September 08, 2010, at 04:10:46 AMIf you mean 80 bit FP (REAL10) then I think from memory that Ray Filiatreault has a string conversion for it.

Yes Hutch, REAL 10 is exactly the point. Windows gcc produces garbage with printf. Linux gcc works properly, because it uses the original GNU libc. Do you have a link at hand? Would be a great help for me.

Quote from: MichaelW September 08, 2010,  at 05:24:00 AIf you don't actually need the additional precision, you can get around the garbage problem by using the FPU to convert the long double into a double.

I know that, Mike. It's a course for students, which will become electrical engineers in a few years. Most of them are assembly language newbies. The boys and girls should know C, because it was examined last semester. The main goal of the course is numerical mathematics and therefore we need the extra precision, to show some strange numerical effects.

Gunther
Forgive your enemies, but never forget their names.

Gunther

I've downloaded the MASM32 package and had a first look. Great job Hutch :U.

I think that my problem can be solved with that great tool. Thank you. It seems, that it'll become my favorite environment for 32 bit low level code.

Gunther
Forgive your enemies, but never forget their names.

clive

Quote from: Gunther
I know that, Mike. It's a course for students, which will become electrical engineers in a few years. Most of them are assembly language newbies. The boys and girls should know C, because it was examined last semester. The main goal of the course is numerical mathematics and therefore we need the extra precision, to show some strange numerical effects.

Consider then 16-bit Microsoft and Borland C compliers, where "long double" was actually 80-bit. Microsoft made "long double" and "double" 64-bit in Win32, with some assorted lame excuses (mainly boils down to cross platform issues with MIPS, PPC, ALPHA, 68K, not using the 80x87). Still I think their PowerStation Fortran supported REAL10.

Last time I looked at some dtoa() source it was pretty ugly if you wanted to handle all possible values/formats.

Also if its a matter of demonstrating the flaws of floating point, and the traps you can fall into, float/double can show those quite effectively too.
It could be a random act of randomness. Those happen a lot as well.

GregL

Gunther,

The function hutch alluded to is FpuFLtoA in the \masm32\fpulib directory, it will convert a REAL10 to a string.




Gunther

Quote from: GregL, September 08, 2010, at 08:40:05 PMThe function hutch alluded to is FpuFLtoA in the \masm32\fpulib directory, it will convert a REAL10 to a string.

I've found it and inspected the code. It's well done and meet my needs.

Quote from: clive, September 08, 2010, at 05:16:20 PMConsider then 16-bit Microsoft and Borland C compliers, where "long double" was actually 80-bit. Microsoft made "long double" and "double" 64-bit in Win32, with some assorted lame excuses

Yes, it's a shame. But it comes even better. The VS 64 bit C/C++  compiler uses by default xmm registers for all floating point operations; that leads to a significant loss of accuracy and will produce some strange results. We'll see that more and more in the future. But gcc has the same behavior. That's dangerous.

Quote from: clive, September 08, 2010, at 05:16:20 PMAlso if its a matter of demonstrating the flaws of floating point, and the traps you can fall into, float/double can show those quite effectively too.

Right. But unfortunately, it's not only a question of demonstration. In their semester work project, the students have to check the GNU libc. I'm very sure it's buggy. Rumors say on the other hand, that the Intel compiler handles REAL 10 in a correct way (load, store, print). I can't test that at the moment.

Gunther
Forgive your enemies, but never forget their names.

raymond

I don't know if the latest version of the fpulib is part of the currently available MASM32 package or whichever one you installed. If the provided Help file is not in .CHM format, it's definitely not the latest one. If the Index page does not show that the latest modifications were made in January 2010, it is not the latest one. You can download the latest one from:

http://www.ray.masmcode.com/fpu.html#fpulib

In adition to expanded parameter sizes for most functions, a special file in that latest package may be of interest to you: the FPUlibtester.exe. It is a dialog box where you can test all the library functions with a variety of input and output size. The output is given in ascii and also shown in hex as it would appear in memory for that output size (may be useful to show how floats are kept in memory or FPU registers).
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

raymond

I also noticed your fractal avatar. If you have any interest in the computation of complex numbers, another library of functions for computing complex numbers is also available on another page of the same site:

http://www.ray.masmcode.com/complex.html

Also available from that page is a fractal generating program which uses the library functions. It can render most hard coded fractals with a magnification up to approx. 1017 (limited by the finite precision of the FPU).
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Gunther

Quote from: raymond, September 09, 2010, at 03:38:10 AMI don't know if the latest version of the fpulib is part of the currently available MASM32 package or whichever one you installed.

Good job, Raymond. I'll check that.

Quote from: raymond, September 09, 2010, at 03:48:44 AMI also noticed your fractal avatar.

That has to do with my principal interest for non-linear system theory. I assume, it's a Win 32 application, isn't it?

Gunther
Forgive your enemies, but never forget their names.

MichaelW

The Cygwin DLL does not depend on MSVCRT, and it treats long double as a REAL10 (although I only had time to test this on printf).

http://www.cygwin.com/faq/faq-nochunks.html#faq.programming.msvs-mingw

makedef.bat:

@echo off
path=C:\MinGW\bin;%path%
@echo on
pexports cygwin1.dll > cygwin1.def
pause

makelib.bat:

\masm32\bin\polib /OUT:cygwin1.lib /DEF:cygwin1.def /MACHINE:ix86
pause

My test source:

;====================================================================
    .486                                ; create 32 bit code
    .model flat, stdcall                ; 32 bit memory model
    option casemap :none                ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\Comctl32.inc
    include \masm32\include\comdlg32.inc
    include \masm32\include\shell32.inc
    include \masm32\include\oleaut32.inc
    include \masm32\include\msvcrt.inc

    include \masm32\macros\macros.asm

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\Comctl32.lib
    includelib \masm32\lib\comdlg32.lib
    includelib \masm32\lib\shell32.lib
    includelib \masm32\lib\oleaut32.lib

    includelib cygwin1.lib

    includelib \masm32\lib\msvcrt.lib
;====================================================================
cygwin_dll_init PROTO C
dll_dllcrt0 PROTO C
printf PROTO C :VARARG
;====================================================================
    .data
        r8  REAL8 ?
        r10 REAL10 ?
    .code
;====================================================================
start:
;====================================================================
    invoke cygwin_dll_init
    invoke dll_dllcrt0
    invoke printf, cfm$("3.141592653589793238462...\n")
    fldpi
    fstp r8
    fldpi
    fstp r10
    invoke printf, cfm$("%.20Lf\n"), r10
    invoke crt_printf, cfm$("%.16f\n\n"), r8

    inkey "Press any key to exit..."
    exit
;====================================================================
end start


3.141592653589793238462...
3.14159265358979323851
3.1415926535897931


BTW, I got the dll from a default installation of Cygwin (~70MB total):

http://www.cygwin.com/

And in case you don't have MinGW, I attached the DEF file.
eschew obfuscation

raymond

QuoteI assume, it's a Win 32 application, isn't it?

Your assumption is 100% correct. :wink
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

clive

Quote from: Gunther
Rumors say on the other hand, that the Intel compiler handles REAL 10 in a correct way (load, store, print). I can't test that at the moment.

An interesting thought, although the last versions I bought and did any validation work on date from 1997/1998 era (2.4, 3.0 and 4.0), so MMX and SSE(1)

The following options seem relevant here


/Qpc32           set internal FPU precision to 24 bit significand
/Qpc64           set internal FPU precision to 53 bit significand (DEFAULT)
/Qpc80           set internal FPU precision to 64 bit significand
/Qrcd            enable fast float-to-int conversions
/Qprec           improve floating-point precision (speed impact less than /Op)
/Qprec_div       improve precision of FP divides (some speed impact)
/Qkscalar        perform 32-bit FP operations using SIMD float instructions
/Qvec            enable vectorizer
/Qlong_double enable 80-bit 'long double'


Give me a minute, I'll compile the example code.

Ok,  I got this, note 16-byte wide "long double", and the printf() is not liking %Lf due to it linking to Microsoft libraries, and the Intel libraries not containing a printf() replacement.

C:\MASM\pi\Intel32>icl -Ox -Qlong_double -Qpc80 pi.c
Intel(R) C/C++ Compiler Version 4.0 98324 Beta-2
Copyright (C) 1985-1998 Intel Corporation.  All rights reserved.


pi.c
Microsoft (R) 32-Bit Incremental Linker Version 5.00.7022
Copyright (C) Microsoft Corp 1992-1997. All rights reserved.

-out:pi.exe
-debug:none
-pdb:none
pi.obj

C:\MASM\pi\Intel32>pi

Layout of data types:
----------------------
Long Double (REAL 10)   = 16 Bytes
Double (REAL 8)         = 8 Bytes
Float (REAL 4)          = 4 Bytes

Compiler Results:
-----------------
PI                      = 3.14159265358979323846264338327 ...
PI as Long Double Value = 0.0000000000000000000
PI as Double Value      = 3.1415926535897931
PI as Float Value       = 3.141593

FPU Results:
------------
FPU control word:       = 137F hex
PI                      = 3.14159265358979323846264338327 ...
PI as Long Double Value = 3.1415920257590524000
PI as Double Value      = 3.1415926535897931
PI as Float Value       = 3.141593
It could be a random act of randomness. Those happen a lot as well.