问题
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.
回答1:
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 doubledata type, and perform your computations asdouble; (this is the only option which is effectively available to users of Microsoft's compiler, because it doesn't really have a distinctlong doubledata type implementation to begin with). - Perform the computation as
long double, but cast the result todoublefor output. - Use C style I/O functions instead of the C++ I/O semantics, and enable MinGW's alternative
printfimplementation 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#definefor any of the latter four to your source, before any#include). If preferred, you may also substitute any earlier compliance level for_XOPEN_SOURCEor_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
snprintffunction to convertlong doubledata to a C string representation, then use C++ semantics to output that instead of leaving C++ to translate the raw form of thelong doubleentity directly. (IIRC, Microsoft don't providesnprintf-- they provide_snprintfinstead -- so if you are careful to use the ANSI function name, you get 80-bitlong doublesupport automatically).
来源:https://stackoverflow.com/questions/30080618/long-double-is-printed-incorrectly-with-iostreams-on-mingw