This is not a MinGW bug ... controversial as that statement may seem, the reality is that it is a limitation of Microsoft's C/C++ runtime library, upon which MinGW is dependent. As a developer, it is incumbent on you to understand the limitations of your tools, such as this one, and to work within those limitations.
The problem you are experiencing is due to Microsoft's lack of any distinct implementation of a long double
data type in MSVC, and the consequent lack of effective support for that data type within the I/O subsystem provided by MSVCRT.DLL; (and, before you tell me, perhaps indignantly, that "of course MSVC supports long double
", I know that it does syntactically, but semantically it has no distinct implementation, simply behaving by effectively ignoring the long
qualifier, such that long double
becomes a synonym for bare double
).
Conversely, GCC and hence MinGW does have an implementation of long double
, which is distinct from double
; the former is an 80-bit entity, whereas the latter is 64-bit, and is an exact analogue of MSVC's 64-bit implementation of both data types. This is great when you need the greater precision of 80-bit floating point computation, but it can lead to problems, such as you are experiencing, when it comes to output of results; (the I/O translator is handed an 80-bit raw data representation of a long double
data entity, where it expects 64-bit; the internal representations are incompatibly different, so garbage ensues when part of the mantissa is interpreted as exponent).
As you've noted, whereas MSVCRT.DLL supports only output of 64-bit double
values, MinGW does offer an alternative implementation of C's printf
style I/O, which can correctly translate the 80-bit format; however, this does not extend to supporting C++ style I/O. Thus, in C++ code, you cannot simply exploit the MinGW alternative I/O implementation, while continuing to use C++ I/O semantics; you have to recognize the MSVCRT.DLL limitation, and code your application accordingly. Some options you might consider include:--
- Forego the use of the
long double
data type, and perform your computations as double
; (this is the only option which is effectively available to users of Microsoft's compiler, because it doesn't really have a distinct long double
data type implementation to begin with).
- Perform the computation as
long double
, but cast the result to double
for output.
- Use C style I/O functions instead of the C++ I/O semantics, and enable MinGW's alternative
printf
implementation by compiling with any of -posix
, -D_GNU_SOURCE
, -D_BSD_SOURCE
, -D_XOPEN_SOURCE=700
, or -D_POSIX_C_SOURCE=200809L
, (or better, add #define
for any of the latter four to your source, before any #include
). If preferred, you may also substitute any earlier compliance level for _XOPEN_SOURCE
or _POSIX_C_SOURCE
; (however, please ignore the incredibly bad advice, which may be offered by some commentators, to compile with -D__USE_MINGW_ANSI_STDIO
; the double underscore, which introduces that macro name, marks it as "implementation reserved", and therefore not something which you, as an end user of the compiler implementation, should be referring to directly).
- Use C's
snprintf
function to convert long double
data to a C string representation, then use C++ semantics to output that instead of leaving C++ to translate the raw form of the long double
entity directly. (IIRC, Microsoft don't provide snprintf
-- they provide _snprintf
instead -- so if you are careful to use the ANSI function name, you get 80-bit long double
support automatically).