int/doubleを文字列に変換する際の速度など

C++でintやdoubleなどの数を文字列(charの配列もしくはstd::string)にしたい時、もしくはその逆で文字列をintやdoubleにしたい時がある。一般的にそのような処理はファイル入出力などと合わせて行われるため、それほど速度を気にすることはなく、むしろ安全な処理を選択することが多いと思う。

そんなわけで、これまではC++のstreamやboost::lexical_castを使っていたのだけれど、これらの時間がかかる処理より速いであろうsnprintfやatoi/strtol、strtodなどとどれほど差があるのかを調べてみた。

以下がざっと書いた速度計測結果。実行は仮想マシンVMWare)上のUbuntu 11.10で行った。何度か測定したところ細かい誤差はあったが、ある程度の傾向は見えたように思う。単純にintをループ内でインクリメンタルする処理を比較対象とした。また、memcpyでintを単純にバイナリとしてcharの配列にコピーする処理も試してみた。

$ g++ -o bench1 bench1.cpp -O3 -march=native

$ time ./bench1 
int -> str snprintf: 1.556647(+0.621571)
int -> str sstream : 1.575977(+0.640901)
int -> str boost   : 1.587728(+0.652652)
int -> str my_itoa : 1.000906(+0.065830)
str -> int atoi    : 1.133539(+0.198462)
str -> int sstream : 1.711099(+0.776023)
str -> int boost   : 2.245375(+1.310299)
dbl -> str snprintf: 2.106724(+1.171648)
dbl -> str sstream : 3.047715(+2.112639)
dbl -> str boost   : 4.116544(+3.181467)
str -> dbl strtod  : 1.500768(+0.565692)
str -> dbl sstream : 2.616993(+1.681917)
str -> dbl boost   : 3.475305(+2.540229)
memcpy(int)        : 0.953762(+0.018685)
increment          : 0.935076(+0.000000)

real    0m45.122s
user    0m24.250s
sys     0m20.457s

intを文字列に変換する際は、snprintf、std::stringstream、boost::lexical_castの3つではそれほど差は見られなかった。自作のmy_itoaはそれなりに高速だが危険な気がするので使いどころが限られるだろう。逆に文字列からintへの変換はstd::stringstreamやboost::lecical_castと比較してatoiが高速だった。strtol+static_castも試してみたがatoiとほぼ同じ速度だった。

doubleを文字列にする場合、intの場合とは異なり、snprintfが他の二つに比べて高速に動作した。反対に文字列をdoubleとして解釈する場合もstrtodが速い。ただし今回の測定では0.0から1.0の間の数しか扱っていないので、その他の場合どう変化するかは分からない。

少し意外だったのは、int/double両方において、snprintfで数を文字列にするよりもatoiやstrtodで文字列を数に変換するほうが速いということだった(数回計測したがこの傾向は変わらなかった)。

以下計測用いたコード。