std :: ostream的浮点格式

Jiv*_*son 38 c++ floating-point cout ostream

如何使用std :: cout执行以下操作?

double my_double = 42.0;
char str[12];
printf_s("%11.6lf", my_double); // Prints " 42.000000"
Run Code Online (Sandbox Code Playgroud)

我准备放弃并使用sprintf_s.

更一般地说,我在哪里可以找到std :: ostream格式的引用,它在一个地方列出所有内容,而不是在长篇教程中全部展开?

编辑2017年12月21日 - 请参阅下面的答案.它使用了我在2012年提出这个问题时无法使用的功能.

Kir*_*rov 68

std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << my_double;
Run Code Online (Sandbox Code Playgroud)

你需要添加

#include <iomanip>
Run Code Online (Sandbox Code Playgroud)

你需要流操纵器

你可以用你想要的任何字符"填充"空白的地方.像这样:

std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) 
          << std::setfill( '0' ) << my_double;
Run Code Online (Sandbox Code Playgroud)

  • +1 包含 include 语句,太多人没有 (2认同)
  • 这是一个很好的 OP 解决方案,但要注意这些是流操纵器;即他们修改流,你必须[恢复它](/sf/ask/159133131/)或将其更改为其他内容当你需要不同的格式时。如果被操作的流是“长期存在的流”,例如`std::cout`、`std::cerr`、日志流等,那么问题就更大了。在这些情况下,使用起来会更方便这里其他答案中建议的解决方案之一。 (2认同)

And*_*rey 14

std::cout << boost::format("%11.6f") % my_double;
Run Code Online (Sandbox Code Playgroud)

你必须 #include <boost\format.hpp>


vit*_*aut 7

在 C++20 中,你将能够做到

double my_double = 42.0;
char str[12];
std::format_to_n(str, sizeof(str), "{:11.6}", my_double); 
Run Code Online (Sandbox Code Playgroud)

或者

std::string s = std::format("{:11.6}", my_double); 
Run Code Online (Sandbox Code Playgroud)

同时,您可以使用{fmt} 库,该提供format_to_n.

免责声明:我是 {fmt} 和 C++20 的作者std::format


Pet*_*ker 6

#include <iostream>
#include <iomanip>

int main() {
    double my_double = 42.0;
    std::cout << std::fixed << std::setw(11)
        << std::setprecision(6) << my_double << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*nze 6

在一般情况下,要避免指定类的东西11,并6在输出点。那是物理标记,而您想要逻辑标记;例如pressurevolume。这样,您可以在一个位置定义压力或体积的格式,并且如果该格式发生更改,则无需搜索整个程序以查找更改格式的位置(也可以不小心更改其他格式)。 。在C ++中,您可以通过定义一个操纵器来做到这一点,该操纵器可以设置各种格式设置选项,最好在完整表达式的末尾还原它们。因此,您最终会编写如下内容:

std::cout << pressure << my_double;
Run Code Online (Sandbox Code Playgroud)

尽管我绝对不会在生产代码中使用它,但我发现以下FFmt格式化程序对快速工作很有用:

class FFmt : public StateSavingManip
{
public:
    explicit            FFmt(
                            int                 width,
                            int                 prec = 6,
                            std::ios::fmtflags  additionalFlags 
                                    = static_cast<std::ios::fmtflags>(),
                            char                fill = ' ' );

protected:
    virtual void        setState( std::ios& targetStream ) const;

private:
    int                 myWidth;
    int                 myPrec;
    std::ios::fmtflags  myFlags;
    char                myFill;
};

FFmt::FFmt(
    int                 width,
    int                 prec,
    std::ios::fmtflags  additionalFlags,
    char                fill )
    :   myWidth( width )
    ,   myPrec( prec )
    ,   myFlags( additionalFlags )
    ,   myFill( fill )
{
    myFlags &= ~ std::ios::floatfield
    myFlags |= std::ios::fixed
    if ( isdigit( static_cast< unsigned char >( fill ) )
             && (myFlags & std::ios::adjustfield) == 0 ) {
        myFlags |= std::ios::internal
    }
}

void
FFmt::setState( 
    std::ios&           targetStream ) const
{
    targetStream.flags( myFlags )
    targetStream.width( myWidth )
    targetStream.precision( myPrec )
    targetStream.fill( myFill )
}
Run Code Online (Sandbox Code Playgroud)

这样可以编写如下内容:

std::cout << FFmt( 11, 6 ) << my_double;
Run Code Online (Sandbox Code Playgroud)

并作记录:

class StateSavingManip
{
public:
    StateSavingManip( 
            StateSavingManip const& other );
    virtual             ~StateSavingManip();
    void                operator()( std::ios& stream ) const;

protected:
    StateSavingManip();

private:
    virtual void        setState( std::ios& stream ) const = 0;

private:
    StateSavingManip&   operator=( StateSavingManip const& );

private:
    mutable std::ios*   myStream;
    mutable std::ios::fmtflags
                        mySavedFlags;
    mutable int         mySavedPrec;
    mutable char        mySavedFill;
};

inline std::ostream&
operator<<(
    std::ostream&       out,
    StateSavingManip const&
                        manip )
{
    manip( out );
    return out;
}

inline std::istream&
operator>>(
    std::istream&       in,
    StateSavingManip const&
                        manip )
{
    manip( in );
    return in;
}
Run Code Online (Sandbox Code Playgroud)

StateSavingManip.cc:

namespace {

//      We maintain the value returned by ios::xalloc() + 1, and not
//      the value itself.  The actual value may be zero, and we need
//      to be able to distinguish it from the 0 resulting from 0
//      initialization.  The function getXAlloc() returns this value
//      -1, so we add one in the initialization.
int                 getXAlloc();
int                 ourXAlloc = getXAlloc() + 1;

int
getXAlloc()
{
    if ( ourXAlloc == 0 ) {
        ourXAlloc = std::ios::xalloc() + 1;
        assert( ourXAlloc != 0 );
    }
    return ourXAlloc - 1;
}
}

StateSavingManip::StateSavingManip()
    :   myStream( NULL )
{
}

StateSavingManip::StateSavingManip(
    StateSavingManip const&
                        other )
{
    assert( other.myStream == NULL );
}

StateSavingManip::~StateSavingManip()
{
    if ( myStream != NULL ) {
        myStream->flags( mySavedFlags );
        myStream->precision( mySavedPrec );
        myStream->fill( mySavedFill );
        myStream->pword( getXAlloc() ) = NULL;
    }
}

void
StateSavingManip::operator()( 
    std::ios&           stream ) const
{
    void*&              backptr = stream.pword( getXAlloc() );
    if ( backptr == NULL ) {
        backptr      = const_cast< StateSavingManip* >( this );
        myStream     = &stream;
        mySavedFlags = stream.flags();
        mySavedPrec  = stream.precision();
        mySavedFill  = stream.fill();
    }
    setState( stream );
}
Run Code Online (Sandbox Code Playgroud)