便携式打印双倍到C++个 iostreams 的指数

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

本文关键字:iostreams 指数 C++ 式打印      更新时间:2023-10-16

我想打印一个双精度值以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-081e-8(如最初所述(,因此符合要求。很抱歉造成混乱。

编辑2:实际上在迪特马尔的评论之后将"尾数"重命名为"指数"。维基百科上还有一个关于尾数与重要部分。

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

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

虽然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
    }
};

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

%e%E 格式说明符将浮点数格式化为十进制尾数和指数。在某些情况下,%g%G格式说明符也会以这种形式设置数字的格式。在以前的版本中,CRT 将始终生成具有三位指数的字符串。例如,printf("%en", 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相比,这是一个差异,C90没有给出任何关于所需指数长度的指示。

请注意,最近的视觉C++更改还涉及如何打印naninf等。