Formato de coma flotante para std:: ostream
¿Cómo hago lo siguiente con std::cout?
double my_double = 42.0;
char str[12];
printf_s("%11.6lf", my_double); // Prints " 42.000000"
Estoy casi listo para renunciar y usar sprintf_s.
Más generalmente, ¿dónde puedo encontrar una referencia sobre el formato std::ostream que enumera todo en un solo lugar, en lugar de extenderlo todo en un largo tutorial?
EDITAR Dic 21, 2017-Ver mi respuesta a continuación. Utiliza características que no estaban disponibles cuando hice esta pregunta en 2012.
6 answers
std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << my_double;
Necesitas agregar
#include <iomanip>
Necesitas manipuladores de flujo
Puedes "llenar" los lugares vacíos con lo que quieras. Así:
std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 )
<< std::setfill( '0' ) << my_double;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-16 15:02:06
std::cout << boost::format("%11.6f") % my_double;
Tienes que #include <boost\format.hpp>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-16 14:40:19
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-16 14:52:25
En general, debe evitar especificar cosas como 11
y 6
en el
punto de salida. Eso es marcado físico, y quieres marcado lógico;
por ejemplo, pressure
, o volume
. De esa manera, se define en un solo lugar
cómo se formatean la presión o el volumen, y si cambia ese formato,
usted no tiene que buscar a través del programa para encontrar dónde cambiar
el formato (y accidentalmente cambiar el formato de otra cosa). En
C++, se hace esto mediante la definición de un manipulador, que establece la diversos
opciones de formato, y preferentemente los restaura al final de la completa
expresion. Así que terminas escribiendo cosas como:
std::cout << pressure << my_double;
Aunque definitivamente no lo usaría en código de producción, he encontrado el
siguiente FFmt
formateador útil para trabajos rápidos:
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 )
}
Esto permite escribir cosas como:
std::cout << FFmt( 11, 6 ) << my_double;
Y para que conste:
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 );
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-16 15:47:58
Soy yo, la OPERACIÓN, Jive Dadson - cinco años después. C++17 se está convirtiendo en una realidad.
El advenimiento de los parámetros de plantilla variádicos con perfect forwarding ha hecho la vida mucho más simple. Se puede prescindir de la locura encadenada de ostream
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-22 20:46:24
Para los futuros visitantes que prefieren especificaciones de formato real estilo printf con std:: ostream, aquí hay otra variación, basada en el excelente post de Martin York en otra pregunta SO: 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);
}
};
Ejemplo de uso:
double my_double = 42.0;
cout << FMT("%11.6f") << my_double << "more stuff\n";
O incluso:
int val = 42;
cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-02 03:09:25