必ず数字が引数に渡されるという限定した状況に限り使用可能な、atoiとatof(数字文字列を数値に変換するC言語関数)を作ってみました。
作ってみたっていうか、こちらの丸パクリして、ほんのちょっとさらに高速にしてみただけですけど。
fast_atof32は小数点以下9桁までしか扱えませんが、整数演算なのでちょっと早いはず。
桁数が少ない場合に使えるかなと。あと浮動小数演算が苦手なCPU向け。
//スペースを取って、符号を返す int _space_sign(const char *s, const char **endptr) { while (*s == 0x20) ++s; int sign = 0; switch (*s) { case '-': sign = -1; // fall through case '+': ++s; break; } *endptr = s; return sign; } //高速版atoi int fast_atoi(const char *s) { int sign = _space_sign(s, &s); int result = 0; while(true) { if(*s > '9' || *s < '0')break; result = result * 10 + *s - '0'; s++; } if (sign != 0) result = -result; return result; } //高速版atof float fast_atof(const char *s) { int sign = _space_sign(s, &s); float result = 0; float cnm = 1; while(true) { if(*s == '.') { s++; break; }else if(*s > '9' || *s < '0')break; result = result * 10 + *s - '0'; s++; } while(true) { if(*s > '9' || *s < '0')break; result = result * 10 + *s - '0'; cnm*=0.1; s++; } if (sign != 0) result = -result; return result * cnm; } //高速版atof(桁が少ない) float fast_atof32(const char *s) { int sign = _space_sign(s, &s); int result = 0; int cnm = 1; while(true) { if(*s == '.') { s++; break; }else if(*s > '9' || *s < '0')break; result = result * 10 + *s - '0'; s++; } while(true) { if(*s > '9' || *s < '0')break; result = result * 10 + *s - '0'; cnm*=10; s++; } if (sign != 0) result = -result; return (float)result / cnm; }
パクリ元との違いはisdigitやisspaceを単純に手書きしただけなんだけど、関数呼び出しを止めるだけでほんのちょっとだけ早くなる。
空白の無い、正の数しかない数字文字列に限定すれば、_space_signも要らなくなるからさらにちょっと早くなる。
ベンチマークを取ってみた。
atoi用データは”123456″
atof用データは””0.01111111″
10,000 * 10,000のループで測定。
VC++2008でビルド。
CPUはCore2Duo E6600 2.4GHz
最適化 有無 | 標準atoi | strtol | fast_atoi | 標準atof | strtod | fast_atof | fast_atof32 |
---|---|---|---|---|---|---|---|
なし | 5,732 | 5,281 | 4,091 | 55,496 | 55,300 | 8,698 | 6,620 |
あり | 5,521 | 5,074 | 1,237 | 55,746 | 57,190 | 5,287 | 3,192 |
数値の単位はミリ秒。
最適化ありのほうはCPUによって違ってくるだろうけど、それにしたって標準関数に比べて早すぎな気がするなぁ。
最適化によってループが省略されたとか?
特にfalst_atofは標準atofに比べて10倍。fast_atof32だと17倍早い。劇的過ぎる。
でもfast_atof32とfast_atofの差は微妙だなぁ。1.6倍か。・・・fast_atof32要らないかも。使いづらいし。
strtolは機能が多いのにatoiより速いんだね。atoi良いとこなし。涙目。
逆にstrtodは微妙にatofに負けてるけど、その差は小さい。つか最適化掛けた方が遅いってどゆこと。
数値変換にsscanfを使う人がいるから、sscanfでも同じ条件で計ってみたんだけど、時間掛かりすぎてたから途中で止めた。
1,000 * 1,000のループにしたら1,000ms位だったから、単純に100,000ms掛かるわけだね。標準atofの2倍。
sscanfは使いやすいけど、一つ変換したいだけなら、素直にatoi/atof使った方がいいっぽいね。
移植性とか安全性とか考えてないので、使い場面は限られますね。
ゲームみたいに、異常データが来ないことが決まっていて、速度が求められるようなケースには結構有効なんじゃないかな。