Przed rozpoczęciem należy sprawdzić, czy w tej funkcji zużywa się znaczny czas. Wykonaj to, mierząc, za pomocą profilera lub w inny sposób. Wiedząc, że nazywasz to milion razy, wszystko jest bardzo dobre, ale jeśli się okaże, że twój program nadal spędza tylko 1% czasu w tej funkcji, to nic, co tu robisz, nie może poprawić wydajności Twojego programu o więcej niż 1%. Gdyby tak było, odpowiedź na twoje pytanie brzmiałaby: "dla twoich celów nie, ta funkcja nie może być znacznie bardziej wydajna i marnujesz swój czas, jeśli spróbujesz".
Po pierwsze, należy unikać s.substr(0, s.size()-1)
. To kopiuje większość ciągu znaków i powoduje, że twoja funkcja nie jest odpowiednia dla NRVO, więc myślę, że generalnie dostaniesz kopię po powrocie. Więc pierwsza zmiana Chciałbym zrobić to wymienić ostatnią linię z:
if(s[s.size()-1] == '.') {
s.erase(s.end()-1);
}
return s;
Ale jeśli wydajność jest poważnym problemem, a oto jak ja to zrobię. Nie obiecuję, że jest to najszybsze z możliwych, ale pozwala uniknąć problemów związanych z niepotrzebnymi alokacjami i kopiowaniem. Każde podejście obejmujące stringstream
będzie wymagało skopiowania z strumienia string do wyniku, więc potrzebujemy bardziej niskiego poziomu operacji, 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;
}
Drugie wywołanie snprintf
zakłada std::string
wykorzystuje ciągły przechowywania. Gwarantuje to C++ 11. Nie jest to gwarantowane w C++ 03, ale jest prawdziwe dla wszystkich aktywnie utrzymywanych implementacji std::string
znanych komitetowi C++. Jeśli wydajność jest naprawdę ważna, to myślę, że rozsądne jest zrobienie tego nieprzenośnego założenia, ponieważ pisanie bezpośrednio do ciągu zapisuje kopiowanie w łańcuchu później.
s.pop_back()
jest C++ 11 sposób powiedzenia s.erase(s.end()-1)
i s.back()
jest s[s.size()-1]
Dla innego możliwym poprawy, można pozbyć się pierwszego zaproszenia do snprintf
i zamiast wielkość swojej s
do pewnej wartości, takich jak std::numeric_limits<double>::max_exponent10 + 14
(w zasadzie długość, której potrzebuje -DBL_MAX
). Problem polega na tym, że przydziela i zeruje znacznie więcej pamięci, niż jest to zwykle potrzebne (322 bajty dla podwójnego IEEE). Mam intuicję, że będzie to wolniejsze od pierwszego połączenia z snprintf
, nie wspominając o marnotrawieniu pamięci w przypadku, gdy wartość zwracana przez ciąg jest utrzymywana przez jakiś czas przez rozmówcę. Ale zawsze możesz to przetestować.
Alternatywnie, std::max((int)std::log10(d), 0) + 14
oblicza rozsądnie ciasne górne ograniczenie wymaganego rozmiaru i może być szybsze niż snprintf
może je dokładnie obliczyć.
Wreszcie może się okazać, że można poprawić wydajność, zmieniając interfejs funkcji. Na przykład, zamiast wrócić nowy ciąg można może dołączyć do łańcucha przechodzi się przez dzwoniącego:
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();
}
}
Następnie dzwoniący może reserve()
dużo miejsca, zadzwoń czynność kilka razy (przypuszczalnie z drugiej łańcuch dołącza się pomiędzy) i zapisz wynikowy blok danych do pliku za jednym razem, bez przydzielania pamięci innej niż reserve
. "Obfitość" nie musi być całym plikiem, może to być jedna linia lub "akapit" na raz, ale wszystko, co unika alokacji pamięci o milionach, może potencjalnie zwiększyć wydajność.
Tytuł wydaje się błędny, powinien być podwójny do napisu? – hyde
oops - tytuł jest cofany. . . oczywiście jest podwójny na ciąg – tpascale
Możliwy duplikat [Formatowanie n cyfr znaczących w C++ bez zapisu naukowego] (http://stackoverflow.com/questions/17211122/formatting-n-significant-digits-in-c-without-scientific- notacja) – mirams