3

Consider the code

#include <iostream>

int main() {
  std::cout << 4.2L;
}

Compiling it on MinGW and running results in the following output:

> g++ test.cc
> a.exe
-7.89773e-278

Is it a bug in MinGW and is there a fix or workaround?

Update:

There is a similar issue with printf described in this question:

#include <cstdio>

int main() {
  std::printf("%Lg", 4.2L); // prints -7.89773e-278
}

However, the issue with printf can be fixed by defining __USE_MINGW_ANSI_STDIO while this one can't, so I think it deserves a separate question.

Community
  • 1
  • 1
vitaut
  • 49,672
  • 25
  • 199
  • 336
  • Maybe is a bug, check the answere to this question [link](http://stackoverflow.com/questions/4089174/printf-and-long-double) – gugu69 May 06 '15 at 15:27
  • That does seem to be nearly the same bug described in the [linked question](http://stackoverflow.com/questions/4089174/printf-and-long-double). MinGW uses the gcc compiler and Microsoft's runtime library; they have different representations for `long double`. The top-scoring answer (not the accepted answer) mentions a workaround for `printf`, using `-D__USE_MINGW_ANSI_STDIO`; I'd be interested in seeing whether there's a similar workaround for `cout << ...`. – Keith Thompson May 06 '15 at 15:36
  • Thanks for the link. I've just checked and a similar issue exists with printf, so it is probably related. – vitaut May 06 '15 at 16:18
  • Unfortunately __USE_MINGW_ANSI_STDIO only fixes printf's output. I've updated the question. – vitaut May 06 '15 at 16:24
  • This code works correctly in mingw-w64 4.9.2 (both 32-bit and 64-bit) – M.M Aug 25 '15 at 02:27

1 Answers1

2

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:--

  1. 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).
  2. Perform the computation as long double, but cast the result to double for output.
  3. 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).
  4. 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).
Keith Marshall
  • 1,980
  • 15
  • 19
  • 1
    Your statement about Microsoft's implementation is incorrect. Microsoft's compiler and runtime *do* implement a `long double` type; it happens to have the same representation as `double` *while still being a distinct type*. Similarly, `short` and `int`, or `int` and `long`, or `long` and `long long` very commonly have the same size, yet they're still distinct types, and nobody says that a compiler doesn't implement `long` if it happens to be the same size as `int`. – Keith Thompson Aug 24 '15 at 23:12
  • 3
    Microsoft's compiler and runtime are consistent and correct; it's the mix of the MS runtime and the gcc compiler that cause this bug in MinGW. – Keith Thompson Aug 24 '15 at 23:12
  • 1
    This is a MinGW bug because it is a bug exhibited by MinGW. Blaming someone else doesn't change that. The MinGW developers could have chosen not to offload the heavy lifting to other functions that do not do the right job. In fact, they did exactly that for the `printf` version, offering the user the option to get compliant behaviour or MS-forwarding-buggy behaviour. – M.M Aug 25 '15 at 02:18
  • So, if you think it is a bug, _file a bug report_; whingeing in a fundamentally irrelevant forum, such as this, achieves nothing. – Keith Marshall Aug 25 '15 at 21:30
  • @KeithMarshall They are writing a comment telling you that you are wrong and you haven't corrected your answer or addressed them, you just ignored their comment. They may well have filed a bug report, but their comment to tell you they think your first sentence is wrong, is entirely legitimate. Really bugs could perhaps be said to propagate upwards , so it's more accurate to identify it as you have, but I think he has a point in not saying that it's not a mingw bug. – barlop Nov 29 '17 at 14:53