Формат плавающей точки для std :: ostream
Как мне сделать следующее: std :: cout?
double my_double = 42.0; char str[12]; printf_s("%11.6lf", my_double); // Prints " 42.000000"
Я просто готов отказаться и использовать sprintf_s.
В более общем плане, где я могу найти ссылку на std :: ostream форматирование, в которой перечислены все в одном месте, а не распространяются все это в длинном учебнике?
- C: Приведение минимального 32-битного целого числа (-2147483648) к float дает положительное число (2147483648.0)
- Float / double precision в режимах отладки / выпуска
- Как мне сделать сравнение с плавающей запятой?
- Как я могу написать функцию питания самостоятельно?
- Ассемблер x86: сравнение с плавающей запятой
EDIT 21 декабря 2017 года – см. Мой ответ ниже. Он использует функции, которые недоступны, когда я задавал этот вопрос в 2012 году.
- Типы с плавающей запятой с фиксированным размером
- Двойной против BigDecimal?
- Float и двойной тип данных в Java
- Сравнение с плавающей точкой `a! = 0.7`
- Разница в арифметике с плавающей запятой между x86 и x64
- Клавиши с плавающей запятой в std: map
- Двойной расчет, создающий нечетный результат
- Как выполнить поразрядную операцию с числами с плавающей запятой
std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << my_double;
Вы должны добавить
#include
Вам нужны streamовые манипуляторы
Вы можете «заполнить» пустые места любым желаемым символом. Как это:
std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << std::setfill( '0' ) << my_double;
std::cout << boost::format("%11.6f") % my_double;
Вы должны #include
#include #include int main() { double my_double = 42.0; std::cout << std::fixed << std::setw(11) << std::setprecision(6) << my_double << std::endl; return 0; }
В общем, вы хотите избежать указания таких элементов, как 11
и 6
в точке вывода. Это физическая разметка, и вам нужна логическая разметка; например, pressure
или volume
. Таким образом, вы определяете в одном месте, как форматируются давление или объем, и если это форматирование изменяется, вам не нужно искать программу, чтобы найти, где изменить формат (и случайно изменить формат чего-то еще) , В C ++ вы делаете это, определяя манипулятор, который задает различные параметры форматирования и предпочитает восстанавливать их в конце полного выражения. Таким образом, вы в конечном итоге пишете такие вещи, как:
std::cout << pressure << my_double;
Хотя я определенно не использовал его в производственном коде, я нашел следующий форматир FFmt
полезный для быстрых заданий:
class FFmt : public StateSavingManip { public: explicit FFmt( int width, int prec = 6, std::ios::fmtflags additionalFlags = static_cast(), 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 ) }
Это позволяет писать такие вещи, как:
std::cout << FFmt( 11, 6 ) << my_double;
И для записи:
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 ); }
это я, OP, Jive Dadson – пять лет спустя. C ++ 17 становится реальностью.
Появление вариационных параметров шаблона с совершенной пересылкой сделало жизнь намного проще. Прикованное безумие ostream << и boost :: format% можно обойти. Функция oprintf ниже заполняет счет. Работа в процессе. Не стесняйтесь отвечать на обработку ошибок и т. Д.
#include #include #include #include namespace dj { template 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)...); 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)...); 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; }
Для будущих посетителей, которые предпочитают использовать спецификации формата printf в стиле std :: ostream, вот еще один вариант, основанный на превосходной почте Мартина Йорка в другом вопросе SO: https://stackoverflow.com/a/535636 :
#include #include #include //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 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); } };
пример использования:
double my_double = 42.0; cout << FMT("%11.6f") << my_double << "more stuff\n";
или даже:
int val = 42; cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";