Beberapa hari yang lalu, anggota StackExchange Anto bertanya tentang kegunaan yang valid untuk operator bit-wise. Saya menyatakan bahwa menggeser lebih cepat daripada mengalikan dan membagi bilangan bulat dengan kekuatan dua. Anggota StackExchange, Daemin membalas dengan menyatakan bahwa penggeseran-kanan menghadirkan masalah dengan angka negatif.
Pada saat itu, saya tidak pernah benar-benar berpikir untuk menggunakan operator shift dengan bilangan bulat yang ditandatangani. Saya terutama menggunakan teknik ini dalam pengembangan perangkat lunak tingkat rendah; oleh karena itu, saya selalu menggunakan bilangan bulat yang tidak ditandatangani. C melakukan pergeseran logis pada bilangan bulat yang tidak ditandai. Tidak ada perhatian yang diberikan pada bit tanda saat melakukan pergeseran logis dengan benar. Bit yang telah diisi diisi dengan nol. Namun, C melakukan operasi pergeseran aritmatika ketika menggeser bilangan bulat yang ditandatangani. Bit yang terisi diisi dengan bit tanda. Perbedaan ini menyebabkan nilai negatif dibulatkan ke arah infinity alih-alih terpotong ke nol, yang merupakan perilaku yang berbeda dari pembagian integer yang ditandatangani.
Beberapa menit pemikiran menghasilkan solusi tingkat pertama. Solusi secara kondisional mengkonversi nilai negatif ke nilai positif sebelum bergeser. Nilai dikonversi secara kondisional kembali ke bentuk negatif setelah operasi shift telah dilakukan.
int a = -5;
int n = 1;
int negative = q < 0;
a = negative ? -a : a;
a >>= n;
a = negative ? -a : a;
Masalah dengan solusi ini adalah bahwa pernyataan tugas bersyarat biasanya diterjemahkan ke setidaknya satu instruksi lompatan, dan instruksi lompatan bisa mahal pada prosesor yang tidak men-decode kedua jalur instruksi. Harus memposisikan ulang sebuah pipa instruksi dua kali membuat penyimpangan yang baik dalam setiap perolehan kinerja yang diperoleh dengan bergeser dari pembagian.
Dengan kata di atas, saya bangun pada hari Sabtu dengan jawaban untuk masalah tugas bersyarat. Masalah pembulatan yang kita alami ketika melakukan operasi pergeseran aritmatika hanya terjadi ketika bekerja dengan representasi komplemen dua. Itu tidak terjadi dengan representasi komplemen seseorang. Solusi untuk masalah ini melibatkan konversi nilai komplemen dua menjadi nilai komplemen seseorang sebelum melakukan operasi shift. Kami kemudian harus mengubah nilai komplemen seseorang kembali ke nilai komplemen dua. Anehnya, kita dapat melakukan serangkaian operasi ini tanpa mengubah nilai negatif sebelum melakukan operasi shift.
int a = -5;
int n = 1;
register int sign = (a >> INT_SIZE_MINUS_1) & 1
a = (a - sign) >> n + sign;
Nilai negatif komplemen dua dikonversi ke nilai negatif komplemen seseorang dengan mengurangi satu. Di sisi lain, nilai negatif komplemen seseorang dikonversi ke nilai negatif komplemen dua dengan menambahkan satu. Kode yang tercantum di atas berfungsi karena bit tanda digunakan untuk mengkonversi dari komplemen dua ke komplemen seseorang dan sebaliknya . Hanya nilai negatif yang akan mengatur bit tanda mereka; oleh karena itu, tanda variabel akan sama dengan nol ketika a positif.
Dengan kata di atas, dapatkah Anda memikirkan peretasan bit-bijaksana lain seperti yang di atas yang telah membuatnya menjadi tas trik Anda? Apa retas bit-bijaksana favorit Anda? Saya selalu mencari peretasan bit-wise-oriented baru.