値の入れ替えコードのパフォーマンス
Java Puzzlers のパズル 7 : フリーマーケット(Swap Meat) の解説に、以下のような一時変数を使わず、排他的論理和を使った値のスワップ(入れ替え)を記述する事は Java でも可能だが、素直なコードよりは遅く動作する事が多い、といった記述がありました。
y = (x ^= (y ^= x)) ^ y;
見た感じは確かになんだかかっこよく見えますね。
なんとなくですがビット演算=早い、というイメージがあったので、読み易さは別として、速度が遅いのは何故なのか気になります。
という事で、以下のようなサンプルコードを書いて実際に速度を計測してみました。
package example; import org.apache.commons.lang.time.StopWatch; public class SwapBenchmark { private static final int ALL_TIMES = 10; private static final int TIMES = 10000000; public static void main(String[] argv) { StopWatch watch = new StopWatch(); for (int i = 0; i < ALL_TIMES; i++) { watch.start(); measureExclusiveOrSwap(); watch.stop(); System.out.printf("XOR Swap Time : %s\n", watch.toString()); watch.reset(); } for (int i = 0; i < ALL_TIMES; i++) { watch.start(); measureSwap(); watch.stop(); System.out.printf("Swap Time : %s\n", watch.toString()); watch.reset(); } } public static void measureExclusiveOrSwap() { int x = 1984; int y = 2001; for (int i = 0; i < TIMES; i++) { y = (x ^= (y ^= x)) ^ y; // 以下アンコメントするとちゃんと値が入れ替わってるのが分かる。 //System.out.printf("x:[%d] y:[%d]%n", x, y); } } public static void measureSwap() { int x = 1984; int y = 2001; int tmp = 0; for (int i = 0; i < TIMES; i++) { tmp = x; x = y; y = tmp; } } }
実行結果は以下のようになりました。
XOR Swap Time : 0:00:00.023 XOR Swap Time : 0:00:00.022 XOR Swap Time : 0:00:00.025 XOR Swap Time : 0:00:00.026 XOR Swap Time : 0:00:00.026 XOR Swap Time : 0:00:00.026 XOR Swap Time : 0:00:00.025 XOR Swap Time : 0:00:00.025 XOR Swap Time : 0:00:00.025 XOR Swap Time : 0:00:00.026 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.010 Swap Time : 0:00:00.009 Swap Time : 0:00:00.009
確かに排他的論理和を使用している方が倍以上遅いようです。
書籍にもありますが、こういったコードは意図を理解しづらいというのが大きなデメリットだとは思うので、パフォーマンス的な利点なども無い以上、こういった書き方はしない方が無難そうですね。
ただ、この速度差の理由が今一つよく分からないままですが・・・最適化?
測定環境
- CPU:Core2Duo 2.66Ghz
- メモリ:4GB
- OS:Windows Vista 32bit
- Java:1.6.0_20