Prima di iniziare, controllare se si impiega tempo significativo in questa funzione. Fatelo misurando, con un profiler o altro. Sapendo che lo chiami un miliardo di volte è tutto molto buono, ma se si scopre che il tuo programma spende ancora solo l'1% del suo tempo in questa funzione, niente di ciò che fai qui può migliorare le prestazioni del tuo programma di oltre l'1%. Se così fosse, la risposta alla tua domanda sarebbe "per i tuoi scopi no, questa funzione non può essere resa significativamente più efficiente e stai sprecando il tuo tempo se provi".
Per prima cosa, evitare s.substr(0, s.size()-1)
. Questa copia la maggior parte della stringa e rende la tua funzione non idonea per NRVO, quindi penso che in genere riceverai una copia al reso. Così il primo cambiamento che vorrei fare è quello di sostituire l'ultima riga con:
if(s[s.size()-1] == '.') {
s.erase(s.end()-1);
}
return s;
Ma se le prestazioni è un problema serio, allora ecco come lo farei. Non sto promettendo che questo è il più veloce possibile, ma evita alcuni problemi con allocazioni e copie non necessarie. Qualsiasi approccio che coinvolge stringstream
richiederà una copia da stringstream al risultato, quindi vogliamo un'operazione più di basso livello, 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;
}
La seconda chiamata a snprintf
presuppone che std::string
utilizza archiviazione contiguo. Questo è garantito in C++ 11. Non è garantito in C++ 03, ma è vero per tutte le implementazioni attivamente mantenute di std::string
note al comitato C++. Se le prestazioni sono davvero importanti, penso che sia ragionevole fare un'ipotesi non portabile, dal momento che scrivere direttamente in una stringa salva la copia in una stringa in un secondo momento.
s.pop_back()
è il modo in C++ 11 di dire s.erase(s.end()-1)
, e s.back()
è s[s.size()-1]
Per un altro possibile miglioramento, si potrebbe eliminare la prima chiamata a snprintf
e invece dimensioni della vostra s
a un valore come std::numeric_limits<double>::max_exponent10 + 14
(in pratica, la lunghezza richiesta da -DBL_MAX
). Il problema è che questo alloca e azzera molta più memoria di quanto sia tipicamente necessario (322 byte per un doppio IEEE). La mia intuizione è che questo sarà più lento della prima chiamata a snprintf
, per non parlare di uno spreco di memoria nel caso in cui il valore di restituzione della stringa viene tenuto in giro per un po 'dal chiamante. Ma puoi sempre provarlo.
In alternativa, std::max((int)std::log10(d), 0) + 14
calcola un limite superiore ragionevolmente stretto sulla dimensione necessaria e potrebbe essere più veloce di snprintf
può calcolarlo esattamente.
Infine, è possibile migliorare le prestazioni modificando l'interfaccia della funzione. Ad esempio, invece di restituire una nuova stringa si potrebbe forse aggiungere a una stringa passata dal chiamante:
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();
}
}
Poi il chiamante può reserve()
un sacco di spazio, chiamare la funzione più volte (presumibilmente con altra stringa aggiunge in tra) e scrivere il blocco di dati risultante nel file tutto in una volta, senza alcuna allocazione di memoria diversa dallo reserve
. "Plenty" non deve essere l'intero file, potrebbe essere una riga o "paragrafo" alla volta, ma tutto ciò che evita un'allocazione di memoria di zillion è un potenziale incremento delle prestazioni.
Il titolo sembra sbagliato, dovrebbe essere il doppio della stringa? – hyde
oops: il titolo è a ritroso. . . naturalmente è doppio rispetto alla stringa – tpascale
Possibile duplicato di [Formattazione di cifre significative in C++ senza notazione scientifica] (http://stackoverflow.com/questions/17211122/formatting-n-significant-digits-in-c-without-scientific- notazione) – mirams