Saya sedang mengerjakan proyek pribadi baru-baru ini ketika saya menemukan masalah aneh.
Dalam loop yang sangat ketat saya memiliki integer dengan nilai antara 0 dan 15. Saya perlu mendapatkan -1 untuk nilai 0, 1, 8, dan 9 dan 1 untuk nilai 4, 5, 12, dan 13.
Saya beralih ke godbolt untuk memeriksa beberapa opsi dan terkejut bahwa sepertinya kompiler tidak dapat mengoptimalkan pernyataan switch dengan cara yang sama seperti rantai if.
Tautannya ada di sini: https://godbolt.org/z/WYVBFl
Kode tersebut adalah:
const int lookup[16] = {-1, -1, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0};
int a(int num) {
return lookup[num & 0xF];
}
int b(int num) {
num &= 0xF;
if (num == 0 || num == 1 || num == 8 || num == 9)
return -1;
if (num == 4 || num == 5 || num == 12 || num == 13)
return 1;
return 0;
}
int c(int num) {
num &= 0xF;
switch (num) {
case 0: case 1: case 8: case 9:
return -1;
case 4: case 5: case 12: case 13:
return 1;
default:
return 0;
}
}
Saya akan berpikir bahwa b dan c akan menghasilkan hasil yang sama, dan saya berharap bahwa saya bisa membaca bit-hacks untuk datang dengan implementasi yang efisien sendiri karena solusi saya (pernyataan switch - dalam bentuk lain) cukup lambat.
Anehnya, b
dikompilasi ke bit-hacks sementara c
itu cukup banyak tidak dioptimalkan atau dikurangi menjadi kasus yang berbeda a
tergantung pada perangkat keras target.
Adakah yang bisa menjelaskan mengapa ada perbedaan ini? Apa cara 'benar' untuk mengoptimalkan kueri ini?
EDIT:
Klarifikasi
Saya ingin solusi beralih menjadi yang tercepat, atau solusi "bersih" yang serupa. Namun ketika dikompilasi dengan optimasi pada mesin saya solusi if secara signifikan lebih cepat.
Saya menulis sebuah program cepat untuk menunjukkan dan TIO memiliki hasil yang sama seperti yang saya temukan secara lokal: Coba online!
Dengan static inline
tabel pencarian sedikit lebih cepat: Cobalah online!
if
masih berdetak switch
(anehnya pencarian menjadi lebih cepat) [TIO untuk mengikuti]
-O3
, dan mengkompilasic
ke sesuatu yang lebih buruk daripadaa
ataub
(c
memiliki dua lompatan bersyarat ditambah beberapa manipulasi bit, vs hanya satu lompatan kondisional dan manipulasi bit yang lebih sederhana untukb
), tetapi masih lebih baik daripada item yang naif dengan tes item. Saya tidak yakin apa yang sebenarnya Anda minta di sini; fakta sederhana adalah bahwa compiler mengoptimalkan dapat mengubah setiap ini menjadi salah satu orang lain jika begitu memilih, dan tidak ada aturan keras dan cepat untuk apa yang akan atau tidak akan melakukan.