便携式打印到C ++ iostreams的double指数

时间:2012-02-10 10:37:05

标签: c++ formatting double iostream platform-independent

我想以std::cout方式(GCC,clang,MSVC ++)打印一个double值,以便所有平台上的输出都相同。

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

#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的评论之后,实际上将“尾数”重命名为“指数”。 There also is a section on Wikipedia on mantissa vs. significant

3 个答案:

答案 0 :(得分:11)

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

我唯一知道的方法是使用自己的std::num_put<char>方面,根据需要格式化值。然后将此方面放入std::localeimbue()依次std::cout加入std::num_put<char>。潜在的实现可以使用默认的snprintf()方面(或{{1}},遗憾的是,可能更简单)来格式化浮点数,然后从指数中去除前导零。

答案 1 :(得分:3)

虽然Dietmar的答案是干净的,可能只是真正便携的答案,但我偶然发现了一个快速而肮脏的答案: MSVC提供_set_output_format函数,您可以使用该函数切换到“将指数打印为两位数”。

可以在main()函数中实例化以下RAII类,以便为您提供与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
    }
};

答案 2 :(得分:2)

问题是Visual C ++没有遵循C99标准。在Visual C ++ 2015中,_set_output_format被删除,因为编译器现在遵循标准:

  

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

     

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

Breaking Changes in Visual C++ 2015。对于旧版本,请参阅@ Manuel的回答。

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

  

选择e,E

     

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

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

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