に機能
inline
を宣言する文字バッファに印刷される文字列をアセンブル(または文字列に呼び出されたときに文字バッファを変換するか、既存の文字列に追加)
開始する前に、この機能でかなりの時間が費やされているかどうかを確認してください。プロファイラーなどで測定してください。何百回も呼び出すことが分かっていることは分かっていますが、プログラムがまだこの関数の1%を費やしているだけであれば、ここで何もプログラムのパフォーマンスを1%以上向上させることはできません。そうした場合、あなたの質問に対する答えは「あなたの目的のためではなく、この機能を大幅に効率化することはできず、試してみるとあなたの時間を無駄にしています。
まずはs.substr(0, s.size()-1)
を避けてください。これにより、ほとんどの文字列とがコピーされますので、あなたの機能はNRVOに適格ではありませんので、通常は返品時にコピーを受け取ると思います。だから私は作ると思います最初の変更はで最後の行を置き換えることです:
if(s[s.size()-1] == '.') {
s.erase(s.end()-1);
}
return s;
しかし、パフォーマンスが深刻な懸念がある場合は、ここで私はそれを行うだろう方法です。私はこれが可能な限り速いと約束しているわけではありませんが、不要な割り当てやコピーの問題を避けています。 stringstream
を含むどのようなアプローチでも、ストリングストリームから結果へのコピーが必要になるため、より低レベルの操作であるsnprintf
が必要です。 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;
}
第二の呼び出しはstd::string
が連続記憶域を使用することを想定しています。これはC++ 11で保証されています。これはC++ 03では保証されていませんが、C++委員会に知られている、アクティブに維持されているすべての実装であるstd::string
に当てはまります。パフォーマンスが本当に重要なのであれば、文字列に直接書き込むと後で文字列にコピーを保存するので、移植性のない仮説を立てることは合理的だと思います。
s.pop_back()
はs.erase(s.end()-1)
を言うのC++ 11の方法である、とs.back()
はあなたのs
のようないくつかの値にサイズの代わりにsnprintf
に最初の呼び出しを取り除くとができ、別の可能向上のためs[s.size()-1]
ですstd::numeric_limits<double>::max_exponent10 + 14
(基本的には、-DBL_MAX
の長さが必要です)。問題は、これにより、通常必要とされるよりもはるかに多くのメモリが割り当てられ、0になります(IEEEの2倍の場合は322バイト)。私の直感は、文字列の戻り値が呼び出し側によってしばらくぶら下がっている場合にメモリが無駄になることは言うまでもなく、これがsnprintf
への最初の呼び出しよりも遅くなるということです。しかし、いつでもテストすることができます。
また、std::max((int)std::log10(d), 0) + 14
は、必要なサイズの合理的にタイトな上限を計算し、snprintf
より正確に計算できる場合があります。
最後に、機能インターフェイスを変更してパフォーマンスを向上させることができます。たとえば、代わりに新しい文字列を返すのあなたは、おそらく、呼び出し側によって渡された文字列に追加することができます:
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();
}
}
その後、発信者は宇宙のreserve()
たくさんのことができ、あなたの関数を呼び出す数回は(おそらく他の文字列として追加します)、そしてreserve
以外のメモリ割り当てをせずに、結果のデータブロックを一度にファイルに書き込むことができます。 "Plenty"はファイル全体である必要はなく、一度に1行または「段落」になる可能性がありますが、膨大なメモリ割り当てを避けることはパフォーマンスの向上につながります。
タイトルが間違っているようですが、文字列に2倍にする必要がありますか? – hyde
oops - タイトルは後方です。 。 。もちろんそれは文字列の2倍です – tpascale
[科学的表記なしでC++でn桁の有効数字を書式設定する]可能な複製(http://stackoverflow.com/questions/17211122/formatting-n-significant-digits-in-c-without-scientific-表記) – mirams