Monday, March 12, 2018

3. Operator Bagian 2





Bitwise AND
Operator AND, &, menghasilkan bit 1 jika kedua operandnya juga bit 1. Menghasilkan bit 0 untuk semua kasus lain. Perhatikan contoh berikut:

00101010   42
   &
00001111   15
----------------
00001010   10


Bitwise OR
Operator OR, |, menghasilkan bit 1 jika minimal salah satu operand adalah bit 1. Menghasilkan bit 0 untuk kasus lain. Perhatikan contoh berikut:

00101010   42
   |
00001111   15
----------------
00101111   47


Bitwise XOR
Operator XOR, ^, menghasilkan bit 1 jika hanya ada satu operand yang memiliki bit 1. Menghasilkan bit 0 pada semua kasus lain. Contoh berikut menampilkan efek dari operator ^. Perhatikan bagaimana pola bit 42 dibalikkan manakala operand kedua memiliki bit 1. Kapanpun operand kedua memiliki bit 0, operand pertama tidak berubah. Anda akan mengetahui bahwa watak ini berguna ketika melakukan sejumlah jenis manipulasi bit.

00101010   42
   ^
00001111   15
----------------
00100101   37


Menggunakan Operator-Operator Bitwise Logikal
Program berikut mendemonstrasikan bagaimana operator-operator bitwise logikal digunakan:

//Mendemonstrasikan operator-operator bitwise logikal
public class LogikaBit {
   public static void main(String args[]) {
      String biner[] = {
         "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
         "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
      };
  
      int a = 3; // 0 + 2 + 1 atau 0011 dalam biner
      int b = 6; // 4 + 2 + 0 atau 0110 dalam biner
      int c = a | b;
      int d = a & b;
      int e = a ^ b;
      int f = (~a & b)|(a & ~b);
      int g = ~a & 0x0f;
  
      System.out.println(" a = " + biner[a]);
      System.out.println(" b = " + biner[b]);
      System.out.println(" a|b = " + biner[c]);
      System.out.println(" a&b = " + biner[d]);
      System.out.println(" a^b = " + biner[e]);
      System.out.println("~a&b|a&~b = " + biner[f]);
      System.out.println(" ~a = " + biner[g]);
   }
}


Pada contoh ini, a dan b memiliki pola bit yang merepresentasikan semua kemungkinan untuk dua dijit biner:0-0, 0-1, 1-0, dan 1-1. Anda dapat melihat bagaimana operator | dan & diterapkan pada tiap bit yang dihasilkan pada c dan d. Nilai yang ditugaskan pada e dan f mengilustrasikan bagaimana operator ^ bekerja. Array string biner memuat semua representasi biner dari 0 sampai 15. Pada contoh ini, array diindeks untuk menunjukkan representasi biner dari tiap hasil. Array dikonstruksi sedemikian rupa sehingga representasi string yang tepar dari sebuah nilai biner n disimpan pada biner[n]. Nilai dari ~a diANDkan dengan 0x0f (0000 1111 pada biner) untuk mereduksi nilainya agar lebih kecil dari 16, sehingg ia dapat ditampilkan menggunakan array biner. Berikut adalah keluaran dari program ini:

 a = 0011
 b = 0110
 a|b = 0111
 a&b = 0010
 a^b = 0101
~a&b|a&~b = 0101
 ~a = 1100


Operator Geser Kiri
Operator geser kiri, <<, menggeser semua bit pada suatu nilai ke kiri sejauh posisi tertentu yang diinginkan. Operator ini memiliki bentuk umum:

nilai << banyak_posisi

Di sini, banyak_posisi menetapkan banyak posisi pergeseran kiri yang akan diterapkan pada nilai. Jadi, operator << menggeser semua bit pada nilai ke kiri sejauh banyak_posisi. Untuk tiap pergeseran, bit orde-tinggi dibuang (hilang), dan bit 0 dimunculkan di sebelah kanan. Ini berarti bahwa ketika pergeseran kiri diterapkan pada operand int, maka semua bit akan hilang digantikan bit 0 jika dilakukan pergeseran sejauh 32 posisi. Jika operandnya bertipe long, maka bit-bitnya akan hilang setelah dilakukan penggeseran sejauh 64 posisi.

Promosi tipe data pada Java menghasilkan nilai yang tak diduga ketika Anda menggeser nilai byte dan short. Seperti Anda ketahui, byte dan short dipromosikan menjadi int ketika sebuah ekspresi dievaluasi. Jadi, hasil dari ekspresi tersebut juga adalah int. Ini berarti bahwa keluaran dari sebuah pergeseran pada nilai byte atau short juga akan bertipe data int, dan bit-bit yang digeser ke kiri tidak akan hilang sampai melewati posisi bit 31. Selanjutnya, nilai byte atau short negatif akan menjadi bertanda jika dipromosikan menjadi int

Jadi, bit-bit orde tinggi akan diisi dengan bit 1. Karena alasan ini, untuk melakukan operasi penggeseran kiri pada byte atau short, Anda perlu membuang byte orde-tinggi dari hasil int. Sebagai contoh, jika Anda melakukan penggeseran kiri terhadap sebuah nilai byte, maka nilai tersebut lebih dahulu dipromosikan menjadi int, baru kemudian penggeseran dilakukan. Ini berarti bahwa Anda perlu membuang tiga byte teratas dari hasil jika apa yang Anda inginkan adalah hasil penggeseran kiri atas nilai byte. Cara paling mudah melakukannya adalah dengan melakukan konversi tipe data eksplisit (cast) hasilnya untuk mengembalikannya menjadi nilai byte. Program berikut mendemonstrasikan konsep ini.

//Menggeser ke kiri sebuah nilai dengan tipe data byte
public class GeserByte {
   public static void main(String args[]) {
      byte a = 64, b;
      int i;
  
      i = a << 2;
      b = (byte) (a << 2);
  
      System.out.println("Nilai semula dari a: " + a);
      System.out.println("i dan b: " + i + " " + b);
   }
}

Keluaran yang dihasilkan program ini diberikan berikut:

Nilai semula dari a: 64
i dan b: 256 0

Karena a dipromosikan menjadi int saat evaluasi dilakukan, penggeseran kiri terhadap nilai 64 (0100 0000) sejauh dua posisi menyebabkan i menjadi bernilai 256 (1 0000 0000). Namun, nilai pada b memuat 0 setelah penggeseran dilakukan, karena byte orde-rendah sekarang bernilai nol. Satu-satunya bit 1 telah dibuang.

Karena setiap operasi penggeseran kiri memiliki efek penggandaan nilai semula, para programer seringkali menggunakan fakta ini sebagai cara alternatif dalam mengalikan 2. Tetapi Anda perlu hati-hati. Jika Anda menggeser sebuah bit 1 ke posisi orde-tinggi (bit 31 atau 63), maka nilai tersebut menjadi negatif. Program berikut mengilustrasikan konsep ini:

//Operasi penggeseran kiri menjadi cara efektif untuk mengalikan 2
public class KaliDua {
   public static void main(String args[]) {
      int i;
      int nilai = 0xFFFFFFE;
  
      for(i=0; i<4; i++) {
       nilai = nilai << 1;
         System.out.println(nilai);
      }
   }
}

Program ini menghasilkan keluran berikut:

536870908
1073741816
2147483632
-32

Dapat diperhatikan bahwa setelah dilakukan penggeseran ke kiri sejauh 4 bit posisi, hasilnya -32.


Operator Geser Kanan
Operator geser kanan, >>, menggeser semua bit pada suatu nilai ke kanan sejauh posisi tertentu yang diinginkan. Operator ini memiliki bentuk umum:

nilai >> banyak_posisi

Di sini, banyak_posisi menetapkan banyak posisi pergeseran kanan yang akan diterapkan pada nilai. Jadi, operator >> menggeser semua bit pada nilai ke kanan sejauh banyak_posisi.

Potongan kode berikut menggeser nilai 32 ke kanan sejauh dua posisi, yang menyebabkan a menjadi 8:

int a = 35;
a = a >> 2;  // a sekarang memuat 8

Lihat operasi biner berikut dengan lebih jelas:

00100011   35
  >>2
00001000  8

Setiap kali sebuah nilai digeser ke kanan, nilainya dibagi dengan dua, dengan membuang sisanya. Pada beberapa kasus, Anda bisa memanfaatkan keuntungan ini sebagai cara alternatif untuk melakukan pembagian integer dengan 2.

Ketika Anda melakukan penggeseran kanan, bit paling kiri akan diisi dengan isi bit paling kiri sebelumnya. Ini dinamakan dengan perluasan tanda dan berperan untuk mempertahankan tanda dari bilangan negatif ketika Anda menggesernya ke kanan. Sebagai contoh, -8>>1 menghasilkan -4, yang dalam biner direpresentasikan:

11111000  -8
  >>1
11111100  -4

Menarik untuk melihat bahwa jika Anda menggeser nilai -1 ke kanan, hasilnya selalu -1, karena perluasan tanda selalh menempatkan bit 1 di posisi bit paling kiri.

Kadangkala perluasan tanda tidak dibutuhkan ketika Anda menggeser sebuah nilai ke kanan. Sebagai contoh, program berikut mengkonversi sebuah nilai byte menjadi representasi string heksadesimalnya. Perhatikan bahwa nilai tergeser dimask dengan cara mengANDkannya dengan 0x0f untuk membuang semua bit perluasan-tanda sehinga nilai tersebut dapat dipakai sebagai indeks pada array yang memuat karakter-karakter heksadesimal.

//Melakukan masking terhadap perluasan tanda
public class ByteHeksa {
   static public void main(String args[]) {
      char heksa[] = {
         '0', '1', '2', '3', '4', '5', '6', '7',
         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
      };
  
      byte b = (byte) 0xf1;
      System.out.println("b = 0x" + heksa[(b >> 4) & 0x0f] + heksa[b & 0x0f]);
   }
}

Program ini menghasilkan keluran berikut:

b = 0xf1


Penggeseran Kiri Tak-Bertanda
Seperti yang telah Anda lihat, operator >> secara otomatis mengisi bit orde-tinggi (bit paling kiri) dengan isi sebelumnya setiap kali penggeseran terjadi. Ini mempertahankan tanda dari nilai. Namun, kadangkala hal ini tidak diinginkan. Sebagai contoh, jika Anda melakukan penggeseran sesuatu yang tidak merepresentasikan nilai numerik, Anda bisa jadi tidak menginginkan perluasan tanda terjadi.

Situasi ini umum terjadi ketika diinginkan untuk menggeser sebuah bit 0 ke bit orde-tinggi, tanpa memandang apapun nilai awalnya. Ini dikenal dengan penggeseran tak-bertanda. Untuk melakukannya, Anda perlu menggunakan operator geser kanan tak-bertanda, >>>, yang selalu menempatkan bit 0 ke bit orde-tinggi.

Fragmen kode berikut mendemonstrasikan operator >>>. Di sini, a ditetapkan bernilai -1, yang memiliki 32 buah bit 1 dalam biner. Nilai ini kemudian digeser sejauh 24 bit, dengan mengisi 24 bit teratas dengan bit 0, dengan mengabaikan perluasan tanda. Ini membuat a menjadi bernilai 255.

int a = -1;
a = a >>> 24;

Ini merupakan operasi yang sama dalam format biner untuk mengilustrasikan apa yang sesungguhnya terjadi:

11111111  11111111  11111111   11111111      -1 dalam biner sebagai sebuah int
>>>24
00000000  00000000  00000000   00000000       255 dalam biner sebagai sebuah int

Operator >>> belum tentu berguna seperti yang Anda perkirakan, karena operator ini hanya bermanfaat pada nilai 32-bit dan 64-bit. Ingat, nilai-nilai yang lebih kecil secara otomatis dipromosikan menjadi int pada ekspresi. Ini berarti bahwa perluasan-tanda terjadi dan penggeseran terjadi pada nilai 32-bit, bukan pada 8-bit atau 64-bit. Program berikut mengilustrasikan efek ini:

//Menggeser tak bertanda atas sebuah nilai byte
public class GeserTakBertanda {
   static public void main(String args[]) {
      char heksa[] = {
         '0', '1', '2', '3', '4', '5', '6', '7',
         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
      };
  
      byte b = (byte) 0xf1;
      byte c = (byte) (b >> 4);
      byte d = (byte) (b >>> 4);
      byte e = (byte) ((b & 0xff) >> 4);
  
      System.out.println(" b = 0x"
         + heksa[(b >> 4) & 0x0f] + heksa[b & 0x0f]);
  
      System.out.println(" b >> 4 = 0x"
         + heksa[(c >> 4) & 0x0f] + heksa[c & 0x0f]);
  
      System.out.println(" b >>> 4 = 0x"
         + heksa[(d >> 4) & 0x0f] + heksa[d & 0x0f]);
  
      System.out.println("(b & 0xff) >> 4 = 0x"
         + heksa[(e >> 4) & 0x0f] + heksa[e & 0x0f]);
   }
}

Ketika program ini dijalankan, dihasilkan keluaran berikut:

 b = 0xf1
 b >> 4 = 0xff
 b >>> 4 = 0xff
(b & 0xff) >> 4 = 0x0f

Keluaran program di atas menunjukkan bagaimana operator >>> sepertinya tidak melakukan apapun ketika menangani byte-byte. Variabel b diberikan sebuah nilai byte negatif. Kemudian c ditugasi nilai byte dari b yang digeser ke kanan sejauh empat posisi, yaitu 0xff karena perluasan tanda. Kemudian d ditugasi nilai byte dari b yang digeser tak-bertanda sejaug empat posisi, yaitu 0x0f, tetapi sebenarnya adalah 0xff karena perluasan tanda yang terjadi ketika b dipromosikan menjadi int sebelum penggeseran. Ekspresi terakhir menetapkan e menjadi nilai byte dari b yang dimask menjadi 8 bit menggunakan operator AND, kemudian hasilnya digeser ke kanan sejauh empat posisi, yang menghasilkan nilai 0x0f.


Penugasan Gabungan Operator Bitwise
Semua operator bitwise biner memiliki bentung kompon atau gabungan yang sama dengan operator-operator aljabar, yang menggabungkan penugasan dengan operasi bitwise. Sebagai contoh, dua statemen berikut, yang menggeser nilai pada a ke kanan sejauh empat bit, adalah ekivalen dengan:

a = a >> 4;
a >>= 4;

Sama halnya, dua statemen berikut, yang menyebabkan nilai pada a ditugasi hasil dari ekspresi bitwise a OR b, adalah ekivalen:

a = a | b;
a |= b;


Operator Penugasan 
Anda telah menggunakan operator penugasan sejak Bab 1. Sekarang saatnya untuk mempelajarinya secara formal. Operator penugasan diwakili dengan satu simbol tanda sama-dengan, =. Operator penugasan dalam Java bekerja hampir sama seperti pada bahasa pemrograman lain. Operator ini memiliki bentuk umum berikut:

var = ekspresi;

Di sini, tipe data dari var harus kompatibel dengan tipe data dari ekspresi.

Operator penugasan memiliki watak menarik yang belum Anda ketahui: operator ini dapat diciptakan untuk melakukan penugasan berantai. Sebagai contoh, perhatikan potongan kode berikut:

int x, y, z;
x = y = z = 100;  // Menetapkan nilai dari x, y, dan z menjadi 100

Fragmen kode ini menetapkan nilai dari variabel x, y, dan z menjadi 100 menggunakan satu statemen. Ini dapat dilakukan karena = adalah operator yang menghasilkan nilai dari ekspresi sebelah-kanan. Jadi, nilai dari z = 100 adalah 100, yang kemudian ditugaskan kepada y, yang hasilnya (100) ditugaskan kepada x.


Operator ?
Java memiliki sebuah operator tiga-cara (ternary) yang dapat menggantikan jenis tertentu dari statemen if-then-else. Operator ini adalah ?, yang memiliki bentuk umum berikut:

ekspresi1 ? ekspresi2 : ekspresi3

Di sini, ekspresi1 dapat berupa sembarang ekspresi yang dievaluasi menjadi sebuah nilai boolean. Jika ekspresi1 bernilai true, maka ekspresi2 akan dievaluasi; sebaliknya, ekspresi3 yang akan dievaluasi. Baik ekspresi2 maupun ekspresi3 harus menghasilkan nilai balik dengan tipe data kompatibel, yang tidak bisa bertipe data void.

Berikut adalah sebuah cara bagaimana operator ? digunakan:

rasio = penyebut == 0 ? 0 : pembilang / penyebut;

Ketika Java mengevaluasi ekspresi penugasan ini, ia pertama-tama melihat ekspresi di sebelah kiri tanda tanya. Jika penyebut bernilai nol, maka ekspresi yang ada di antara tanda tanya dan titik-dua akan dievaluasi dan dipakai sebagai nilai dari keseluruhan ekspresi ?. Jika penyebut tidak sama dengan nol, maka ekspresi setelah titik-dua akan dievaluasi dan dipakai sebagai nilai dari keseluruhan ekspresi ?. Hasil yang diperoleh oleh operator ? kemudian ditugaskan kepada rasio.

Berikut adalah sebuah program yang mendemonstrasikan operator ?. Program ini menggunakan operator tersebut untuk memperoleh nilai absolut dari sebuah variabel.

//Mendemonstrasikan operator ternary (?)
public class Ternary {
   public static void main(String args[]) {
      int i, k;
      i = 10;
  
      k = i < 0 ? -i : i; // mendapatkan nilai absolut dari i
      System.out.print("Nilai absolut dari ");
      System.out.println(i + " adalah " + k);
  
      i = -10;
      k = i < 0 ? -i : i; // mendapatkan nilai absolut dari i
      System.out.print("Absolute value of ");
      System.out.println(i + " is " + k);
   }
}

Keluaran program ditampilkan di sini:

Nilai absolut dari 10 adalah 10
Absolute value of -10 is 10


Keutamaan Operator
Tabel 3.1 menampilkan urutan keutamaan untuk operator-operator Java, dari tertinggi sampai terendah. Operator-operator pada baris yang sama berderajat sama dalam keutamaan. Pada operasi-operasi biner, urutan evaluasi dilakukan dari kiri ke kanan (kecuali penugasan, yang dievaluasi dari kanan ke kiri). Meskipun secara teknis berperan sebagai separator, [ ], ( ), dan . juga dapat berperan sebagai operator.

Tabel 3.1 Derajat keutamaan operator-operator Java
Tertinggi






++ (postfiks)
-- (postfiks)





++ (prefiks)
-- (prefiks)
~
?
+ (unary)
- unary
(cast)
*
/
%




+
-





>> 
>>> 
<< 




> 
>=
< 
<=
instanceof


==
!=





&






^






|






&&






||






?:






->






=
op=





Terendah








Menggunakan tanda kurung ()
Tanda kurung meningkatkan keutamaan dari operasi yang ada di dalamnya. Ini seringkali diperlukan untuk mendapatkan hasil yang Anda inginkan. Sebagai contoh, perhatikan ekspresi berikut:

a >> b + 3

Ekspresi ini pertama-tama menambahkan 3 pada b dan kemudian menggeser a ke kanan sejauh nilai dari b. Jadi, ekspresi ini dapat dituliskan ulang menggunakan tanda kurung seperti ini:

a >> (b + 3)

Namun, jika Anda ingin lebih dahulu menggeser a sejauh b posisi dan kemudian menambahkan 3 pada hasil tersebut, Anda perlu menggunakan tanda kurung seperti ini:

(a >> b) + 3

Selain dipakai untuk meningkatkan keutamaan, tanda kurung juga dipakai untuk memperjelas makna ekspresi. Bagi pembaca program, ekspresi yang kompleks bisa jadi sulit dimengerti. Dengan menambahkan tanda kurung pada ekspresi kompleks, pembaca program dapat lebih mudah memahaminya. Sebagai contoh, ekspresi mana yang lebih mudah dibaca?

a | 4 + c >> b & 7
(a | (((4 + c) >> b) & 7))

No comments: