Portable printing of exponent of a double to C++ iostreams

后端 未结 3 1582
鱼传尺愫
鱼传尺愫 2021-02-05 12:28

I want to print a double value to std::cout portably (GCC, clang, MSVC++) such that the output is the same on all platforms.

I have a problem with the forma

相关标签:
3条回答
  • 2021-02-05 13:10

    While Dietmar's answer is the clean and probably only really portable answer, I accidentally found a quick-and-dirty answer: MSVC provides the _set_output_format function which you can use to switch to "print exponent as two digits".

    The following RAII class can be instantiated in your main() function to give you the same behaviour of GCC, CLANG and MSVC.

    class ScientificNotationExponentOutputNormalizer
    {
    public:
        unsigned _oldExponentFormat;
    
        ScientificNotationExponentOutputNormalizer() : _oldExponentFormat(0)
        {
    #ifdef _MSC_VER
            // Set scientific format to print two places.
            unsigned _oldExponentFormat = _set_output_format(_TWO_DIGIT_EXPONENT);
    #endif
        }
    
        ~ScientificNotationExponentOutputNormalizer()
        {
    #ifdef _MSC_VER
            // Enable old exponent format.
            _set_output_format(_oldExponentFormat);
    #endif
        }
    };
    
    0 讨论(0)
  • 2021-02-05 13:24

    There is no manipulator controlling the formatting of the exponent (I assume you mean the exponent rather than the mantissa; also, the "official" name used for the mantissa is significant). To make matters worse, I can't see any rule in the C standard which restricts the formatting of the exponent. I realize that this is about C++ but for the purpose of the formatting details, the C++ standard refers to the C standard.

    The only approach I'm aware of is to use an own std::num_put<char> facet which formats the values as desired. This facet would then be put into a std::locale which in turn is imbue()ed into std::cout. A potential implementation could use the default std::num_put<char> facet (or snprintf() which is, unfortunately, probably simpler) to format the floating point number and then strip leading zeros from the exponent.

    0 讨论(0)
  • 2021-02-05 13:24

    The problem is that Visual C++ was not following the C99 standard. In Visual C++ 2015, _set_output_format was removed since the compiler now follows the standard:

    The %e and %E format specifiers format a floating point number as a decimal mantissa and exponent. The %g and %G format specifiers also format numbers in this form in some cases. In previous versions, the CRT would always generate strings with three-digit exponents. For example, printf("%e\n", 1.0) would print 1.000000e+000. This was incorrect: C requires that if the exponent is representable using only one or two digits, then only two digits are to be printed.

    In Visual Studio 2005 a global conformance switch was added: _set_output_format. A program could call this function with the argument _TWO_DIGIT_EXPONENT, to enable conforming exponent printing. The default behavior has been changed to the standards-conforming exponent printing mode.

    See Breaking Changes in Visual C++ 2015. For older versions, see @Manuel's answer.

    FYI, in the C99 standard, we can read:

    e,E

    A double argument representing a floating-point number is converted in the style [-]d.ffffd e(+-)dd, where there is one digit (which is nonzero if the argument is nonzero) before the decimal-point character and the number of digits after it is equal to the precision; if the precision is missing, it is taken as 6; if the precision is zero and the # flag is not specified, no decimal-point character appears. The value is rounded to the appropriate number of digits. The E conversion specifier produces a number with E instead of e introducing the exponent. The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent. If the value is zero, the exponent is zero. A double argument representing an infinity or NaN is converted in the style of an f or F conversion specifier.

    This is a difference compared to C90 that did not give any indication concerning the required exponent length.

    Note that the recent Visual C++ changes also concern how to print nan, inf etc.

    0 讨论(0)
提交回复
热议问题