Java, bazı noktada, program akışının iki int değişkenleri, "a" ve "b", sıfır olmayan olup olmadığı tarafından belirlendiği bazı kod yazıyorum (not: a ve b asla negatif ve asla tamsayı taşma aralığında).
İle değerlendirebilirim
if (a != 0 && b != 0) { /* Some code */ }
Veya alternatif olarak
if (a*b != 0) { /* Some code */ }
Kod parçasının çalışma başına milyonlarca kez çalışmasını beklediğimden hangisinin daha hızlı olacağını merak ediyordum. Ben büyük bir rasgele oluşturulan dizi onları karşılaştırarak deneyi yaptım ve ben de dizi (veri kesir = =) sonuçları ne kadar etkilediğini görmek için merak ettim:
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);
}
Ve sonuçlar, "a" veya "b" nin zamanın ~% 3'ünden 0'a eşit olmasını beklerseniz, a*b != 0
bundan daha hızlı olduğunu gösterir a!=0 && b!=0
:
Nedenini merak ediyorum. Biraz ışık tutabilen var mı? Derleyici mi yoksa donanım düzeyinde mi?
Düzenleme: Meraktan ... şimdi şube tahmini hakkında öğrendim, ben bir OR b için analog karşılaştırma göstermek ne olacağını merak ediyordum :
Şube tahmininin beklendiği gibi etkisini görüyoruz, ilginç bir şekilde grafik X ekseni boyunca biraz çevriliyor.
Güncelleme
1- !(a==0 || b==0)
neler olduğunu görmek için analize ekledim .
2- Ben de dahildir a != 0 || b != 0
, (a+b) != 0
ve (a|b) != 0
meraktan, dallanma tahmini öğrenmeye sonra. Ancak mantıksal olarak diğer ifadelere eşdeğer değildir, çünkü doğruya dönmek için yalnızca ORb'nin sıfırdan farklı olması gerekir, bu nedenle işlem verimliliği için karşılaştırılmaları amaçlanmaz.
3- Analiz için kullandığım gerçek ölçütü de ekledim, ki bu sadece keyfi bir int değişkeni yineliyor.
4- Bazı insanlar a != 0 & b != 0
bunun aksine a != 0 && b != 0
, daha yakın davranacağını a*b != 0
öngörerek, şube tahmin etkisini ortadan kaldıracağımızı tahmin etmeyi önerdiler. &
Boole değişkenleriyle kullanılabileceğini bilmiyordum , sadece tamsayılarla ikili işlemler için kullanıldığını düşündüm.
Not: Tüm bunları düşündüğüm bağlamda, int taşması bir sorun değil, ama genel bağlamlarda kesinlikle önemli bir husustur.
İşlemci: Intel Core i7-3610QM @ 2.3GHz
Java sürümü: 1.8.0_45
Java (TM) SE Çalışma Zamanı Ortamı (derleme 1.8.0_45-b14)
Java HotSpot (TM) 64 Bit Sunucu VM (derleme 25.45-b02, karışık mod)
a != 0 & b != 0
.
a*b!=0
bir şubesi daha az
(1<<16) * (1<<16) == 0
ancak her ikisi de sıfırdan farklıdır.
a*b
eğer sıfırdır biri arasında a
ve b
sıfırdır;a|b
yalnızca ikisi birden olduğunda sıfırdır.
if (!(a == 0 || b == 0))
? Mikrobenç işaretler kötü bir şekilde güvenilmezdir, bunun gerçekten ölçülebilir olması olası değildir (~% 3 bana bir hata payı gibi geliyor).