in einer Header-Datei deklarieren
Bevor Sie beginnen, prüfen Sie, ob in dieser Funktion viel Zeit verbraucht wird. Tun Sie dies, indem Sie entweder mit einem Profiler oder auf andere Weise messen. Zu wissen, dass Sie es eine Zillion Mal nennen, ist alles sehr gut, aber wenn es sich herausstellt, dass Ihr Programm nur 1% seiner Zeit in dieser Funktion verbringt, dann kann nichts, was Sie hier tun, Ihre Programmleistung um mehr als 1% verbessern. Wenn das der Fall wäre, wäre die Antwort auf Ihre Frage "für Ihre Zwecke nein, diese Funktion kann nicht wesentlich effizienter gemacht werden und Sie verschwenden Ihre Zeit, wenn Sie es versuchen".
Zuerst, vermeiden Sie s.substr(0, s.size()-1)
. Dies kopiert die meisten der Zeichenfolge und es macht Ihre Funktion für NRVO nicht in Frage, so dass ich denke, in der Regel erhalten Sie eine Kopie bei der Rückkehr. So ist die erste Änderung, die ich machen würde, ist die letzte Zeile zu ersetzen:
if(s[s.size()-1] == '.') {
s.erase(s.end()-1);
}
return s;
Aber wenn Leistung ein ernstes Problem ist, dann ist hier, wie ich es tun würde. Ich verspreche nicht, dass dies die schnellste Möglichkeit ist, aber es vermeidet einige Probleme mit unnötigen Zuweisungen und Kopieren. Jeder Ansatz, der stringstream
einbezieht, wird eine Kopie vom Stringstream zum Ergebnis erfordern, also wollen wir eine Low-Level-Operation, snprintf
.
static std::string dbl2str(double d)
{
size_t len = std::snprintf(0, 0, "%.10f", d);
std::string s(len+1, 0);
// technically non-portable, see below
std::snprintf(&s[0], len+1, "%.10f", d);
// remove nul terminator
s.pop_back();
// remove trailing zeros
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
// remove trailing point
if(s.back() == '.') {
s.pop_back();
}
return s;
}
Der zweite Aufruf von snprintf
nimmt an, dass std::string
sequenzielle Speicher verwendet. Dies ist in C++ 11 garantiert. Es ist nicht in C++ 03 garantiert, aber gilt für alle aktiv gepflegten Implementierungen von std::string
, die dem C++ - Komitee bekannt sind. Wenn Leistung wirklich wichtig ist, dann ist es vernünftig, diese nicht portable Annahme zu machen, da das direkte Schreiben in eine Zeichenkette später das Kopieren in eine Zeichenkette spart.
s.pop_back()
ist die C++ 11 Art und Weise s.erase(s.end()-1)
zu sagen, und s.back()
ist s[s.size()-1]
Für eine andere möglich Verbesserung, Sie loswerden dem ersten Aufruf von snprintf
bekommen konnte und stattdessen Größe Ihre s
auf einen Wert wie std::numeric_limits<double>::max_exponent10 + 14
(im Grunde die Länge, die -DBL_MAX
benötigt). Das Problem ist, dass dies viel mehr Speicher reserviert und löscht, als normalerweise benötigt wird (322 Bytes für ein IEEE-Double). Meine Intuition ist, dass dies langsamer sein wird als der erste Anruf an snprintf
, ganz zu schweigen von verschwenderischem Speicher in dem Fall, in dem der String-Rückgabewert für eine Weile vom Anrufer gehalten wird. Aber du kannst es immer testen.
Alternativ std::max((int)std::log10(d), 0) + 14
berechnet eine relativ enge Obergrenze für die benötigte Größe und möglicherweise schneller als snprintf
kann es genau berechnen.
Schließlich kann es sein, dass Sie die Leistung durch Ändern der Funktionsschnittstelle verbessern können. Zum Beispiel, anstatt eine neue Zeichenfolge zurückkehren könnten Sie vielleicht in einem String anhang vom Anrufer übergeben:
void append_dbl2str(std::string &s, double d) {
size_t len = std::snprintf(0, 0, "%.10f", d);
size_t oldsize = s.size();
s.resize(oldsize + len + 1);
// technically non-portable
std::snprintf(&s[oldsize], len+1, "%.10f", d);
// remove nul terminator
s.pop_back();
// remove trailing zeros
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
// remove trailing point
if(s.back() == '.') {
s.pop_back();
}
}
Dann kann der Anrufer reserve()
vielen Platz, rufen Sie Ihre Funktion mehrmals (vermutlich mit anderer Zeichenfolge anhängt in zwischen), und schreiben Sie den resultierenden Datenblock in die Datei auf einmal, ohne andere Speicherzuweisung als die reserve
. "Plenty" muss nicht die ganze Datei sein, es könnte eine Zeile oder ein "Absatz" gleichzeitig sein, aber alles, was eine Unmenge von Speicherzuweisungen vermeidet, ist ein potenzieller Leistungsschub.
Der Titel scheint falsch, sollte doppelt zu string sein? – hyde
oops - Titel ist rückwärts. . . natürlich ist es doppelt zu string – tpascale
Mögliches Duplikat von [Formatierung n signifikante Ziffern in C++ ohne wissenschaftliche Notation] (http://stackoverflow.com/questions/17211122/formatting-n-significant-digits-in-c-without-scientific- Notation) – mirams