15

我想将双精度值打印到std::cout可移植(GCC、clang、MSVC++),这样所有平台上的输出都是相同的。

我对指数的格式有疑问。以下程序

#include <iostream>
int main()
{
    std::cout << 0.1e-7 << std::endl;
    return 0;
}

GCC 有这个输出:

1e-08

以及 MSVC 的以下输出

1e-008

如何使两个输出相同?

如果这是一个愚蠢的问题,我很抱歉,但到目前为止我还没有找到答案。所有格式似乎都围绕尾数之前所有内容的格式演变......

编辑: GCC 的输出1e-08不是1e-8(如最初所述),因此它符合要求。对困惑感到抱歉。

EDIT2:实际上在 Dietmar 的评论之后将“尾数”重命名为“指数”。维基百科上还有一个关于尾数与显着的部分

4

3 回答 3

11

没有操纵器控制指数的格式(我假设您的意思是指数而不是尾数;此外,用于尾数的“官方”名称很重要)。更糟糕的是,我在 C 标准中看不到任何限制指数格式的规则。我意识到这是关于 C++ 但出于格式化细节的目的,C++ 标准是指 C 标准。

我知道的唯一方法是使用自己的std::num_put<char>方面来根据需要格式化值。然后将这个方面放入 astd::locale中,然后将其imbue()放入中std::cout。一个潜在的实现可以使用默认std::num_put<char>方面(或者snprintf()不幸的是,它可能更简单)来格式化浮点数,然后从指数中去除前导零。

于 2012-02-10T10:51:05.090 回答
3

虽然 Dietmar 的答案是干净且可能唯一真正便携的答案,但我意外地找到了一个快速而肮脏的答案:MSVC 提供了_set_output_format可用于切换到“将指数打印为两位数”的功能。

可以在您的函数中实例化以下 RAII 类,main()以提供与 GCC、CLANG 和 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
    }
};
于 2012-02-10T12:16:15.837 回答
2

问题是 Visual C++ 没有遵循 C99 标准。在 Visual C++ 2015 中,_set_output_format由于编译器现在遵循标准,因此已将其删除:

%eand格式说明符将%E浮点数格式化为十进制尾数和指数。在某些情况下,%gand%G格式说明符还会以这种形式格式化数字。在以前的版本中,CRT 总是会生成具有三位指数的字符串。例如,printf("%e\n", 1.0) 将打印1.000000e+000. 这是不正确的:C 要求如果指数只能使用一位或两位数字表示,则只打印两位数字

在 Visual Studio 2005 中添加了一个全局一致性开关:_set_output_format. 程序可以使用参数调用此函数_TWO_DIGIT_EXPONENT,以启用符合要求的指数打印。默认行为已更改为符合标准的指数打印模式

请参阅Visual C++ 2015 中的重大更改。对于旧版本,请参阅@Manuel 的回答。

仅供参考,在C99 标准中,我们可以阅读:

e,E

表示浮点数的双精度参数以 [-]d.ddd e(+-)dd 样式转换,其中在小数点字符和后面的位数等于精度;如果精度缺失,则取6;如果精度为零且未指定 # 标志,则不出现小数点字符。该值四舍五入到适当的位数。E 转换说明符产生一个带有 E 而不是 e 引入指数的数字。指数始终包含至少两位数字,并且仅包含表示指数所需的更多数字. 如果该值为零,则指数为零。表示无穷大或 NaN 的双参数以 f 或 F 转换说明符的样式进行转换。

与 C90 相比,这是一个差异,它没有给出任何有关所需指数长度的指示。

请注意,最近的 Visual C++ 更改还涉及如何打印naninf

于 2016-03-02T04:19:52.420 回答