ฉันกำลังเขียนโค้ดบางส่วนใน Java ที่ ณ จุดหนึ่งการไหลของโปรแกรมจะถูกกำหนดโดยตัวแปร 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
จากความอยากรู้หลังจากการเรียนรู้เกี่ยวกับการทำนายสาขา แต่พวกเขาจะไม่เทียบเท่ากับการแสดงออกอื่น ๆ ในเชิงตรรกะเพราะมีเพียงออร์เดอร์ b เท่านั้นที่จะต้องไม่ใช่ศูนย์ที่จะคืนค่าจริงดังนั้นจึงไม่ได้ถูกนำมาเปรียบเทียบเพื่อประสิทธิภาพการประมวลผล
3- ฉันยังเพิ่มเกณฑ์มาตรฐานที่แท้จริงที่ฉันใช้สำหรับการวิเคราะห์ซึ่งเป็นเพียงการวนซ้ำตัวแปรภายในโดยพลการ
4- บางคนแนะนำให้รวมa != 0 & b != 0
เมื่อเทียบa != 0 && b != 0
กับการคาดการณ์ว่ามันจะทำงานอย่างใกล้ชิดa*b != 0
เพราะเราจะลบผลการทำนายสาขา ฉันไม่รู้ว่า&
สามารถใช้กับตัวแปรบูลีนได้ฉันคิดว่ามันใช้สำหรับการทำงานแบบไบนารีที่มีจำนวนเต็มเท่านั้น
หมายเหตุ: ในบริบทที่ฉันกำลังพิจารณาทั้งหมดนี้ int มากเกินไม่ใช่ปัญหา แต่นั่นเป็นการพิจารณาที่สำคัญในบริบททั่วไป
CPU: Intel Core i7-3610QM @ 2.3GHz
เวอร์ชั่น 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<<16) * (1<<16) == 0
แต่ทั้งคู่ต่างจากศูนย์
a*b
เป็นศูนย์ถ้าหนึ่งของa
และb
เป็นศูนย์; a|b
เป็นศูนย์เฉพาะถ้าทั้งคู่เป็น
if (!(a == 0 || b == 0))
อะไร Microbenchmarks นั้นไม่น่าเชื่อถือและไม่น่าจะวัดได้จริง ๆ (ประมาณ 3% ฟังดูเหมือนข้อผิดพลาดเล็กน้อยสำหรับฉัน)