Setelah berkenalan dengan operator bitwise, kita berpindah ke operator yang menggerakkan posisi bit itu sendiri. Operator shift menggeser seluruh pola bit sebuah bilangan ke kiri atau ke kanan sejumlah posisi tertentu — secara praktik, menggeser kiri mengalikan dengan pangkat dua dan menggeser kanan membagi dengan pangkat dua. Java menyediakan tiga operator: << (left shift), >> (signed right shift), dan >>> (unsigned right shift). Perbedaan >> dan >>> hanya terlihat pada bilangan negatif, dan di situlah letak kejutan yang paling sering menangkap pemula — semua angka pada Chapter ini kita verifikasi langsung dari eksekusi nyata.

Tiga Operator Shift #

Operator a << n menggeser bit a sebanyak n posisi ke kiri; posisi kosong di kanan diisi nol, sehingga nilainya menjadi a * 2^n. Operator a >> n menggeser ke kanan dengan menjaga tanda: posisi kosong di kiri diisi salinan bit tanda, sehingga bilangan negatif tetap negatif. Operator a >>> n mengabaikan tanda sepenuhnya — posisi kosong selalu diisi nol, sehingga hasilnya layaknya bilangan tak bertanda (unsigned).

java GeserBit.java
public class GeserBit {
    public static void main(String[] args) {
        int a = 16;

        System.out.println("a       = " + a);
        System.out.println("a << 2  = " + (a << 2));   // 16 x 2^2 = 64
        System.out.println("a >> 2  = " + (a >> 2));   // 16 / 2^2 = 4

        int negatif = -8;
        System.out.println("negatif      = " + negatif);
        System.out.println("negatif >> 1 = " + (negatif >> 1));    // -4, tanda dipertahankan
        System.out.println("negatif >>> 1 = " + (negatif >>> 1));  // 2147483644, tanda dibuang

        System.out.println("1 << 31 = " + (1 << 31));              // meluap batas int
    }
}

Output yang Dihasilkan:

text
a       = 16
a << 2  = 64
a >> 2  = 4
negatif      = -8
negatif >> 1 = -4
negatif >>> 1 = 2147483644
1 << 31 = -2147483648

Mari kita telaah baris-baris kode di atas:

  1. Baris 6 (a << 2): bit 10000 (16) bergeser dua posisi menjadi 1000000 — nilai 64, sama dengan 16 * 2^2.
  2. Baris 7 (a >> 2): bit bergeser kembali menghasilkan 4, sama dengan 16 / 2^2.
  3. Baris 11 (negatif >> 1): -8 dibagi dua menjadi -4 — bit tanda ikut disalin sehingga hasil tetap negatif.
  4. Baris 12 (negatif >>> 1): bit tanda dibuang dan diganti nol, menghasilkan 2147483644 — bilangan positif raksasa yang muncul dari bilangan negatif kecil.
  5. Baris 14 (1 << 31): bit tunggal digeser sampai posisi tanda, menghasilkan -2147483648 — nilai terkecil yang sanggup ditampung int.

Membaca Bit yang Bergeser #

Angka -8 pada contoh sebelumnya memiliki representasi biner 11111111111111111111111111111000 — 32 bit dengan hampir semuanya bernilai 1. Ketika >> menggeser satu posisi ke kanan, bit tanda 1 disalin ke posisi paling kiri sehingga pola tetap didominasi angka 1 dan hasilnya -4. Ketika >>> menggeser pola yang sama, nol masuk dari kiri sehingga angka 1 di posisi tanda hilang dan hasilnya berubah menjadi positif. Method Integer.toBinaryString memperlihatkan seluruh drama ini bit demi bit.

public class RepresentasiBit {
    public static void main(String[] args) {
        int nilai = -8;

        System.out.println("-8       : " + Integer.toBinaryString(nilai));
        System.out.println("-8 >> 1  : " + Integer.toBinaryString(nilai >> 1));
        System.out.println("-8 >>> 1 : " + Integer.toBinaryString(nilai >>> 1));
        System.out.println("1 << 31  : " + Integer.toBinaryString(1 << 31));
        System.out.println("1 << 3   : " + Integer.toBinaryString(1 << 3));
    }
}

Output yang Dihasilkan:

text
-8       : 11111111111111111111111111111000
-8 >> 1  : 11111111111111111111111111111100
-8 >>> 1 : 1111111111111111111111111111100
1 << 31  : 10000000000000000000000000000000
1 << 3   : 1000

Tiga baris pertama pada output memperlihatkan pergeseran yang sama pada pola bit ...11111000. Hasil -8 >> 1 tetap 32 bit penuh angka 1 di depan, sedangkan -8 >>> 1 hanya menyisakan 31 bit — toBinaryString memang tidak mencetak nol di depan, jadi satu nol terdepan hasil >>> tidak tampil. Baris keempat menegaskan kenapa 1 << 31 bernilai negatif: satu-satunya bit yang hidup tepat berada di posisi bit tanda.

Operator <<, >>, dan >>> melengkapi kotak peralatan level bit kita. Berikutnya kita mundur sejenak ke operator yang paling sering Anda tulis tanpa menyadarinya: operator unary — tanda plus dan minus, komplemen bit, serta pasangan ++ dan -- dengan perbedaan halus postfix melawan prefix.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

GeserBit.java

Unduh berkas
java
public class GeserBit {
    public static void main(String[] args) {
        int a = 16;

        System.out.println("a       = " + a);
        System.out.println("a << 2  = " + (a << 2));   // 16 x 2^2 = 64
        System.out.println("a >> 2  = " + (a >> 2));   // 16 / 2^2 = 4

        int negatif = -8;
        System.out.println("negatif      = " + negatif);
        System.out.println("negatif >> 1 = " + (negatif >> 1));    // -4, tanda dipertahankan
        System.out.println("negatif >>> 1 = " + (negatif >>> 1));  // 2147483644, tanda dibuang

        System.out.println("1 << 31 = " + (1 << 31));              // meluap batas int
    }
}

RepresentasiBit.java

Unduh berkas
java
public class RepresentasiBit {
    public static void main(String[] args) {
        int nilai = -8;

        System.out.println("-8       : " + Integer.toBinaryString(nilai));
        System.out.println("-8 >> 1  : " + Integer.toBinaryString(nilai >> 1));
        System.out.println("-8 >>> 1 : " + Integer.toBinaryString(nilai >>> 1));
        System.out.println("1 << 31  : " + Integer.toBinaryString(1 << 31));
        System.out.println("1 << 3   : " + Integer.toBinaryString(1 << 3));
    }
}