C++17 Möglichkeiten/Library zum Formatieren von Fließkommazahlen?
-
Hallo zusammen,
ich möchte Fließkommazahlen in std::string konvertieren, dazu gibt es eine legacy-Funktion, deren Signatur ich nicht ändern kann:
std::string float_to_string( double value, unsigned int precision, char decimal_point, char thousands_separator );
Die naive C++ Implementation über
std::ostringstream
undstd::locale
#include <string> #include <locale> #include <iostream> #include <sstream> #include <iomanip> std::string float_to_string( double value, unsigned int precision, char decimal_point, char thousands_separator ) { struct fmt_locale : std::numpunct<char> { char_type DecimalPoint = '.'; char_type ThousandsSeparator = ','; string_type Grouping = "\3"; fmt_locale( char_type dp, char_type ts ) : DecimalPoint( dp ), ThousandsSeparator ( ts ) { } char_type do_decimal_point() const override { return DecimalPoint; } char_type do_thousands_sep() const override { return ThousandsSeparator; } string_type do_grouping() const override { return Grouping; } }; std::locale loc( std::locale::classic(), new fmt_locale( decimal_point, thousands_separator ) ); std::ostringstream oss; oss.imbue( loc ); oss << std::fixed << std::setprecision( precision ) << value; return oss.str(); }
ist schnarchlangsam. Die Lösungen, die ich bisher gefunden habe, unterstützen keine Tausender-Trennzeichen, kennt jemand eine schnelle C++ Lösung?
Ich könnte jetzt natürlich statische Variablen benutzen, um Heapallokationen zu minimieren, das Ganze dann auch noch threadsafe verkapseln, aber das scheint mir für eine so simple Aufgabe ziemlich viel Overhead zu sein.
-
-
Prinzipiell nichts, aber fmt ist genauso sperrig. Wenn man den Dezimal- und Tausendertrenner angeben möchte, muss man das wieder über eine Locale machen, und dann wieder über eine eigene numpunct Klasse. Überzeugt mich bis jetzt nicht, vllt muss ich mich aber mal weiter damit beschäftigen.
-
Und wie wäre es da mit einer C-artigen Lösung mittels
sprintf_s
undsetlocale
?Gut den Dezimalpunkt müsstest du von Hand korrgieren und ebenso die Tausendertrennzeichen von Hand einfügen. Dafür sehe ich aber die Zwischendaten komplett auf dem Stack, da man die notwendigen C Arrays sauber in ihren Größen abschätzen kann.
-
@DocShoe sagte in C++17 Möglichkeiten/Library zum Formatieren von Fließkommazahlen?:
Prinzipiell nichts, aber fmt ist genauso sperrig.
Wobei du ja nach Geschwindigkeit und nicht nach Sperrigkeit gefragt hattest...
Außerdem ist es weniger sperrig, da man das locale demfmt::format
als Parameter übergeben kann:fmt::format(loc, ">{:L}<", f);
Für die 3 Zahlen 10000000.234 / 1.234 / 1.1 bekomme ich dann:
>10.000.000,234< >1,234< >1,1<
Leider geht sowas wie
{:.02f}
nicht mitL
zu verbinden (oder ich bin zu blöd), denn{:.02L}
funktioniert nicht wie gewünscht, das .2 scheint hier die Gesamtlänge statt die Dezimalstellen zu beeinflussen. Es kommt dann raus:>1e+07< <-- das will ich so natürlich nicht haben >1,2< <-- und auch hier sollten es 2 Stellen sein >1,1< <-- und hier hätte ich gerne 1,10
Bleibt wohl nur,
{:.02f}
zu nutzen und dann manuell den Punkt durch das Komma zu ersetzen und das Tausender-Zeichen einzufügen.Zum Spielen: https://godbolt.org/z/54dfz5eoW
-
@wob Das
f
muss wohl ganz zum Schluss stehen:
https://hackingcpp.com/cpp/libs/fmt.html>{:.2Lf}<
>10.000.000,23< >1,23< >1,10<
-
Habe jetzt was mit ner lokalen statischen Variable gebaut, das funktioniert schon mal als in place Ersatz.
Aber fmt ist interessant, das behalte ich auf jeden Fall im Auge.
-
@DNKpp sagte in C++17 Möglichkeiten/Library zum Formatieren von Fließkommazahlen?:
@wob Das f muss wohl ganz zum Schluss stehen:
Oh, danke! Ich dachte, ich hätte das ausprobiert. Habe ich wohl falsch probiert. Aber sehr schön, dass es geht!