私はJavaでいくつかのコードを書いています。ある時点で、プログラムのフローは、2つのint変数「a」と「b」が非ゼロであるかどうかによって決定されます(注:aとbが負になることはありません。整数オーバーフローの範囲内には決してありません)。
私はそれを評価することができます
if (a != 0 && b != 0) { /* Some code */ }
または代わりに
if (a*b != 0) { /* Some code */ }
私はそのコードが実行ごとに数百万回実行されることを期待しているので、どちらがより高速になるのか疑問に思いました。ランダムに生成された巨大な配列でそれらを比較することによって実験を行い、配列のスパース性(データの割合= 0)が結果にどのように影響するかを知りたくもありました。
long time;
final int len = 50000000;
int arbitrary = 0;
int[][] nums = new int[2][len];
for (double fraction = 0 ; fraction <= 0.9 ; fraction += 0.0078125) {
for(int i = 0 ; i < 2 ; i++) {
for(int j = 0 ; j < len ; j++) {
double random = Math.random();
if(random < fraction) nums[i][j] = 0;
else nums[i][j] = (int) (random*15 + 1);
}
}
time = System.currentTimeMillis();
for(int i = 0 ; i < len ; i++) {
if( /*insert nums[0][i]*nums[1][i]!=0 or nums[0][i]!=0 && nums[1][i]!=0*/ ) arbitrary++;
}
System.out.println(System.currentTimeMillis() - time);
}
そして、結果は、「a」または「b」が0に等しいと予想される場合、時間の約3%以上が、a*b != 0
よりも速いことを示していa!=0 && b!=0
ます。
その理由を知りたいです。誰かが光を当てることができますか?それはコンパイラですか、それともハードウェアレベルですか?
編集: 好奇心から...分岐予測について学んだので、OR bのアナログ比較がゼロでないことを示すのではないかと思っていました。
予想と同じように分岐予測の効果がわかります。興味深いことに、グラフはX軸に沿って多少反転しています。
更新
1- !(a==0 || b==0)
何が起こるかを確認するために分析に追加しました。
2 -私も含めa != 0 || b != 0
、(a+b) != 0
そして(a|b) != 0
好奇心のうち、分岐予測についての学習の後。ただし、他の式と論理的に同等ではありません。trueを返すために必要なのはOR b だけであり、処理効率を比較するためのものではありません。
3-分析に使用した実際のベンチマークも追加しました。これは、任意のint変数を反復するだけです。
4-一部の人々は、とはa != 0 & b != 0
対照的にを含めることを提案しa != 0 && b != 0
ていましたa*b != 0
。分岐予測効果を削除するため、より密接に動作すると予測されました。私は&
それがブール変数で使用できることを知りませんでした、それは整数でのバイナリ演算にのみ使用されると思いました。
注:このすべてを検討していた状況では、intオーバーフローは問題ではありませんが、これは一般的な状況では間違いなく重要な考慮事項です。
CPU:Intel Core i7-3610QM @ 2.3 GHz
Javaバージョン:1.8.0_45
Java(TM)SEランタイム環境(ビルド1.8.0_45-b14)
Java HotSpot(TM)64ビットサーバーVM(ビルド25.45-b02、混合モード)
a != 0 & b != 0
。
a*b!=0
ブランチが1つ少ない
(1<<16) * (1<<16) == 0
しかし、どちらもゼロとは異なります。
a*b
ゼロならばである1のa
及びb
ゼロです。a|b
両方の場合にのみゼロです。
if (!(a == 0 || b == 0))
ですか?マイクロベンチマークは信頼性が低いことで悪名高く、これが実際に測定可能である可能性は低いです(約3%は、私にとって誤差の範囲のように聞こえます)。