Floating point format for std::ostream
Asked Answered
B

8

56

How do I do the following with std::cout?

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

I am just about ready to give up and use sprintf_s.

More generally, where can I find a reference on std::ostream formatting that lists everything in one place, rather than spreading it all out in a long tutorial?

EDIT Dec 21, 2017 - See my answer below. It uses features that were not available when I asked this question in 2012.

Bari answered 16/8, 2012 at 14:28 Comment(9)
The format specifier for printf should be "%11.6f". There's no "lf" format specifier, and "Lf" would be for long double.Fractional
@pete - Well you learn something every day. I have been using %lf for 28 years.Bari
@Pete @Jive: There is nothing wrong with using %lf; the l is simply ignored according to the standard. See pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html, or your favorite C spec.Malmsey
@JiveDadson - don't want to go to far off on this tangent, but is that with the same compiler, or spread across various ones?Fractional
@pete Everything from the PCC ca. 1984 to VC++ 2010 about five minutes ago.Bari
@PeteBecker: There is a "lf" format specifier. From the C99 standard, "[the "l" modifier] has no effect on a following a, A, e, E, f, F, g, or G conversion specifier." In other words, "lf" means the same as "f".Neutretto
As @Malmsey pointed out, the 'l' is ignored here, so formally it's valid.Fractional
The reason %lf exists is so one can use the same format string for scanf and printf. You have to tell scanf whether the arg is a float (%f) or a double (%lf). Get it wrong and your program goes kablooey.Bari
wow, all that work to merely print a float, and people complained that printf was complicated.Kaddish
P
90
std::cout << std::fixed << std::setw(11) << std::setprecision(6) << my_double;

You need to add

#include <iomanip>

You need stream manipulators

You may "fill" the empty places with whatever char you want. Like this:

std::cout << std::fixed << std::setw(11) << std::setprecision(6) 
          << std::setfill('0') << my_double;
Popple answered 16/8, 2012 at 14:30 Comment(6)
Which ones? Where do I put the 11 and where do I put the 6?Bari
To match the original format specifier this also needs std::setw(11). And as a side note, for the specific case of a precision of 6, you don't need to say it, neither in C nor C++, because it's the default.Fractional
@JiveDadson - sorry, I missed the 11. Edited.Popple
@JiveDadson - it is, by default. I just mentioned, that could be customized.Popple
+1 for including the include statement, too many people don'tTmesis
This is a great solution to the OP, but be aware that these are stream manipulators; i.e they modify the stream and you will have to revert it or change it to something else each time you need a different format. It is more of a problem if the stream being manipulated is a "long-living one", like std::cout, std::cerr, logging stream, etc. In those cases it will be less cumbersome to use one of the solutions suggested in other answers here.Embracery
I
14
std::cout << boost::format("%11.6f") % my_double;

You have to #include <boost\format.hpp>

Interpretative answered 16/8, 2012 at 14:40 Comment(1)
I remember I used to use that long ago on a project far, far away. Thanks for reminding me. I wish I could use boost for what I am working on, but alas...Bari
E
13

In C++20 you can to do

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

or

std::string s = std::format("{:11.6}", my_double); 

In pre-C++20 you can use the {fmt} library that provides an implementation of format_to_n.

Disclaimer: I'm the author of {fmt} and C++20 std::format.

Execution answered 14/7, 2020 at 16:24 Comment(0)
N
8

In general, you want to avoid specifying things like 11 and 6 at the point of output. That's physical markup, and you want logical markup; e.g. pressure, or volume. That way, you define in a single place how pressure or volume are formatted, and if that formatting changes, you don't have to search through out the program to find where to change the format (and accidentally change the format of something else). In C++, you do this by defining a manipulator, which sets the various formatting options, and preferrably restores them at the end of the full expression. So you end up writing things like:

std::cout << pressure << my_double;

Although I definitly wouldn't use it in production code, I've found the following FFmt formatter useful for quicky jobs:

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 )
}

This allows writing things like:

std::cout << FFmt( 11, 6 ) << my_double;

And for the record:

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

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 );
}
Noninterference answered 16/8, 2012 at 15:47 Comment(1)
That's some mighty nice stuff, and I thank you. To everybody: I have to leave for a while. Thanks for all the help. It appears there is no perfect answer, but I have learned a lot, and even remembered some things I had forgotten. When I get back I will struggle with where to put the green check mark.Bari
F
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;
}
Fractional answered 16/8, 2012 at 14:52 Comment(14)
Not quite what I need. Maybe I asked the question wrong. I want it always to print 11 characters, no more, no less. When I give that 0.1, it prints "0.100000" which is only 8 characters.Bari
@JiveDadson - works fine for me. When I give that 0.1 it prints " 0.100000", which is 11 characters. (Note that there are three leading spaces in the actual output; they seem to have gotten swallowed in word wrapping.Fractional
Note that setw(11) does not set the output to be exactly 11 characters. It sets the field width to be at least 11 characters. E.g., printing 42e5 with this format produces 14 characters.Argentum
This is driving me bonkers. It's so easy with printf, and so short. I might just have to rip off boost/format, as Andrey suggested. I have despised iostreams since the first day they were introduced. I have fought this battle a lot of times, but I always forget the devilish details.Bari
@JiveDadson - yes, it's verbose. If you're going to do the same thing frequently (i.e. more than once), write a manipulator that does it. Still not as simple as printf, of course.Fractional
When I added std::setfill(' ') to the mix, it worked on the first number, then reverted.Bari
"11 characters, no more, no less"? The format specifier in the original example doesn't do that. More important, what do you want it to do when the displayed value won't fit in 11 characters? (42e5, as @EricPostpischil mentioned)Fractional
@JiveDadson: And, please, use en.cppreference.com/w/cpp/io/manip/setprecision as C++ reference.Committee
The values will never overflow 11 places, so it's moot, but if by accident one would not fit, I would want the formatter to behave the way %11.6f does. @SChepurin, thanks for the link.Bari
Wait a minute. I think it's the setw(11) that is only working for the first number then being forgotten.Bari
setw isn't sticky. It gets cleared after the next insertion. So if you're inserting more than one value with the same statement, you have to repeat it.Fractional
I can't repeat it without changing the interface. I tried cout.width(11), but that was not sticky either. I think I give up now. Will either sneak boost/format into the thing or roll my own equivalent. Did I mention that I detest iostreams?Bari
std::cout << std::setw(11) << foo << std::setw(11) << bar;Fractional
@JiveDadson - "if by accident one would not fit, I would want the formatter to behave the way %11.6f does" -- the code I gave you does that. Both forms set the minimum field width. If the value is too large for that width they will produce more characters as needed.Fractional
W
2

For future visitors who prefer actual printf-style format specs with std::ostream, here is yet another variation, based on Martin York's excellent post in another SO question: https://stackoverflow.com/a/535636:

#include <iostream>
#include <iomanip>
#include <stdio.h> //snprintf

class FMT
{
public:
    explicit FMT(const char* fmt): m_fmt(fmt) {}
private:
    class fmter //actual worker class
    {
    public:
        explicit fmter(std::ostream& strm, const FMT& fmt): m_strm(strm), m_fmt(fmt.m_fmt) {}
//output next object (any type) to stream:
        template<typename TYPE>
        std::ostream& operator<<(const TYPE& value)
        {
//            return m_strm << "FMT(" << m_fmt << "," << value << ")";
            char buf[40]; //enlarge as needed
            snprintf(buf, sizeof(buf), m_fmt, value);
            return m_strm << buf;
        }
    private:
        std::ostream& m_strm;
        const char* m_fmt;
    };
    const char* m_fmt; //save fmt string for inner class
//kludge: return derived stream to allow operator overloading:
    friend FMT::fmter operator<<(std::ostream& strm, const FMT& fmt)
    {
        return FMT::fmter(strm, fmt);
    }
};

usage example:

double my_double = 42.0;
cout << FMT("%11.6f") << my_double << "more stuff\n";

or even:

int val = 42;
cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";
Weakling answered 2/2, 2018 at 3:9 Comment(1)
Are you not worried, that m_fmt might point to something already gone in some use cases? I would err on the side of caution and make that member a std::string i.e. a copy.Aedile
B
1

it's me, the OP, Jive Dadson - five years on. C++17 is becoming a reality.

The advent of variadic template parameters with perfect forwarding has made life so much simpler. The chained madness of ostream<< and boost::format% can be dispensed with. The function oprintf below fills the bill. Work in progress. Feel free to chime in on error-handling, etc...

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <string_view>

namespace dj {

    template<class Out, class... Args>
    Out& oprintf(Out &out, const std::string_view &fmt, Args&&... args) {
        const int sz = 512;
        char buffer[sz];
        int cx = snprintf(buffer, sz, fmt.data(), std::forward<Args>(args)...);

        if (cx >= 0 && cx < sz) { 
            return out.write(buffer, cx);
        } else if (cx > 0) {
            // Big output
            std::string buff2;
            buff2.resize(cx + 1);
            snprintf(buff2.data(), cx, fmt.data(), std::forward<Args>(args)...);
            return out.write(buff2.data(), cx);
        } else {
            // Throw?
            return out;
        }
    }
}

int main() {
    const double my_double = 42.0;
    dj::oprintf(std::cout, "%s %11.6lf\n", "My double ", my_double);
    return 0;
}
Bari answered 22/12, 2017 at 20:32 Comment(1)
Using a string_view as an input for C-style functions is dangerous as it is not necessarily null-terminated.Clary
P
0

Some great answers already; kudos to those!

This is based on some of them. I have added type assertions for POD types, since they are the only safe types usable with printf().

#include <iostream>
#include <stdio.h>
#include <type_traits>

namespace fmt {
namespace detail {

template<typename T>
struct printf_impl
{
    const char* fmt;
    const T v;

    printf_impl(const char* fmt, const T& v) : fmt(fmt), v(v) {}
};

template<typename T>
inline typename std::enable_if<std::is_pod<T>::value, std::ostream& >::type
operator<<(std::ostream& os, const printf_impl<T>& p)
{
    char buf[40];
    ::snprintf(buf, sizeof(buf), p.fmt, p.v, 40);
    return os << buf;
}

} // namespace detail

template<typename T>
inline typename std::enable_if<std::is_pod<T>::value, detail::printf_impl<T> >::type
printf(const char* fmt, const T& v)
{
    return detail::printf_impl<T>(fmt, v);
}

} // namespace fmt

Example usage it as below.

std::cout << fmt::printf("%11.6f", my_double);

Give it a try on Coliru.

Platto answered 2/10, 2020 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.