pow(x, 2) vs (x * x) どっちが速いか
プログラムを書いていて少し気になることがありました。べき乗を求めるpowという関数がありますが、二乗の場合はpow(x, 2)と書くのと(x * x)と書くので、どちらが速く実行されるのでしょうか。早速ベンチマークを取ってみようということになりました。
僕の予想としては、コンパイラが最適化してくれるおかげでどちらでも同じ結果が得られるだろうという予想です。皆さんはどうでしょうか。結果は続きをどうぞ。
ベンチマークの環境は以下のとおりです。
- コンパイラ: M$ VC2005 Express Edition
- コンパイラオプション 主に/O2 /arch:SSE2(その他はmakefileVC8参照)
- ソースコードはpow2_test.cpp
- 開発、実行環境はThinkPad X60s (Core Duo L2400 1.66GHz + RAM 2GB) + M$ Windows XP SP2
ベンチマークのとり方に問題がある可能性がありますが、結果は(x * x)の圧勝でした。
項目 | 時間 [cycle] |
---|---|
pow(x, 2) | 761990720 |
(x * x) | 83377840 |
コンパイラはそこまで賢くないのでしょうか? アセンブラpow2_test.asmを見るとtest1(=> pow(x, 2))とtest2(=> (x * x))で違うコードが吐かれていることが確認できます。今度gccでも試してみようと思います。
ちなみに時間計測について参考にさせて戴いたのは、WATARU's MEMO 『RDTSC 命令 --凄いぞ、64ビットカウンター!--』と『- read-time stamp counter (RDTSC)命令の利用方法 -』です。ありがとうございました。
コメント
double pow(double x, double y)なので(ですよね?)、pow(x,2)はpow(x,2.0)とキャストされて渡されるわけで、これをx*xと解釈するのはむずかしい気がします。
というわけで普段x*xを使っているのですが、
例えば、(a+b+c)^2が欲しいときに、
(a+b+c)*(a+b+c)とやるか、
x=a+b+c;としておいてx*xとやるかはよく迷います。
後者が速い気がしますが、めんどうなので。
それは最適化してもらえるのかな。
>hajimeさん
VC6での検証、ありがとうございます。両方定数なら、というのが曲者ですね。片方が定数の場合(今回は2のみ)の展開もサポートしてくれると嬉しいよね、というのがこのお題の本質でした。
>cataclyさん
確かに標準的なC言語ではpow(double, double)となっていますが、C++ではオーバーロード(引数の型や数が別なら同一名でも複数の定義が可能)の機能があるので、pow(double, int)というのが隠れてあったりします。その証拠にアセンブラ出力を見ると、今回は内部的には_Pow_intというテンプレート関数が呼び出されていることが確認できると思います。
(x * x)の件ですが、xが簡単の場合は最適化がかかると思いますが、複雑な場合は怪しいですね。これも試してみる価値があると思います。
コメントする
- 匿名でのコメントは受け付けておりません。
- お名前(ハンドル名可)とメールアドレスは必ず入力してください。
- メールアドレスを表示されたくないときはURLも必ず記入してください。
- コメント欄でHTMLタグは使用できません。
- コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
- コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。
- 投稿ボタンを押してエラーがでなければ、投稿は成功しています。反映されるまでには少し時間がかかります。
私も気になったのでVisual C++ 6.0で計測してみました。
Posted by: hajime : March 3, 2008 01:47 AM結果としては、
・powの片方にでも変数が入ると展開してくれない
・両方定数(constでも可)なら展開する
・volatileが付くと最適化防止がかかるので展開してくれない
といったところでしょうか。
そこまで深いチェックはしてないので間違ってるかも知れませんが・・・。まぁ。予想通りではあります。