Saturday, December 24, 2016

Bab 3. Pemrograman C# Belajar Dari Contoh



3. Operator




C# menyediakan beberapa operator yang memberikan programer kendali atas konstruksi dan evaluasi ekspresi. Kebanyakan operator C# diklasifikasikan dalam kategori berikut: aritmatik, bitwise, relasional, logikal. Semua operator tersebut akan diperiksa dan dibahas pada bab ini. Operator penugasan dan operator ? juga akan didiskusikan. C# juga mendefinisikan beberapa operator lain untuk menangani situasi khusus, seperti pengindeksan array, pengaksesan anggota, dan operator lambda. Situasi khusus tersebut akan lebih detil dibahas nanti pada buku ini.


Operator Aritmatik

C# mendefinisikan beberapa operator aritmatik berikut ini:

Operator
Arti
+
Penjumlahan
-
Pengurangan
*
Perkalian
/
Pembagian
%
Modulus
++
Inkremen
--
Dekremen

Operator +, -, *, dan / bekerja sesuai dengan yang diharapkan dan dapat diterapkan pada sembarang tipe data numerik built-in.

Meskipun semua operator aritmatik telah banyak dikenal, beberapa situasi khusus perlu mendapat perhatian. Pertama, ingat bahwa ketika / diterapkan pada sebuah integer, maka sisa pembagian akan dibuang; misalnya, 10/3 akan sama dengan 3 dalam pembagian integer. Anda bisa mendapatkan sisa pembagian ini menggunakan operator modulus %. Operator % disebut pula dengan operator sisa (remainder). Operator ini menghasilkan sisa dari suatu pembagian integer. Misalnya, 10%3 adalah 1. Dalam C#, operator % dapat diterapkan pada tipe integer maupun tipe titik-mengambang. Jadi, 10.0%3 juga menghasilkan 1. (Hal ini berbeda dari C/C, yang hanya mengijinkan operasi modulus diterapkan pada tipe integer). Program berikut mendemonstrasikan operator modulus.

// Demonstrasi operator %.
using System;

class DemoMod {

    static void Main() {
        int ihasil, isisa;
        double dhasil, dsisa;

        ihasil = 10 / 3;
        isisa = 10 % 3;

        dhasil = 10.0 / 3.0;
        dsisa = 10.0 % 3.0;

        Console.WriteLine("Hasil dan sisa pembagian dari 10 / 3: " +
                           ihasil + " " + isisa);

        Console.WriteLine("Hasil dan sisa pembagian dari 10.0 / 3.0: " +
                           dhasil + " " + dsisa);
    }
}

Keluaran dari program ini ditampilkan di sini:

Hasil dan sisa pembagian dari 10 / 3: 3 1
Hasil dan sisa pembagian dari 10.0 / 3.0: 3.33333333333333 1


Inkremen dan Dekremen
Dikenalkan pada Bab 1, operator inkreman ++ dan operator dekreman – akan dibahas kembali di sini. Seperti yang akan Anda lihat, keduanya memiliki beberapa sifat khusus yang menarik. Pembahasan akan dimulai dengan apa yang dilakukan kedua operator tersebut.

Operator inkreman menambahkan 1 pada operandnya, dan operator dekreman mengurangi 1 dari operandnya. Oleh karena itu,

x = x + 1;

sama dengan

x++;

dan

x = x – 1;

sama dengan

x--;

Perlu dipahami bahwa dalam format inkremen dan dekremen, x dievaluasi hanya sekali, bukan dua kali. Hal ini bisa memperbaiki efisiensi dalam beberapa kasus.

Kedua operator inkremen dan dekremen dapat memprefiks atau mempostfiks operand. Sebagai contoh,

x = x + 1;

dapat ditulis-ulang sebagai

++x;  // format prefiks

atau sebagai

x++;  // format postfiks

Dalam program sebelumnya, tidak ada perbedaan bila inkremen diterapkan sebagai prefiks ataupun postfiks. Namun, ketika operator inkremen atau dekremen dipakai sebagai bagian dari ekspresi yang lebih besar, perbedaan penting terjadi. Ketika operator inkremen atau dekremen memprefiks operandnya, hasil dari operasi tersebut adalah nilai dari operand setelah diinkremen atau didekremen. Ketika operator inkremen atau dekremen mempostfiks operandnya, hasil dari operasi tersebut adalah nilai dari operand sebelum diinkremen atau didekremen. Perhatikan berikut:

x = 10;
y = ++x;

Pada kasus ini, y akan menjadi bernilai 11. Ini dikarenakan x terlebih dahulu diinkremen dan kemudian nilainya dijadikan nilai balik. Tetapi, jika kode tersebut dituliskan sebagai

x = 10;
y = x++;

maka y akan bernilai 10. Pada kasus ini, nilai dari x terlebih dahulu diperoleh, diinkremen sebesar 1, dan nilai asli dari x dijadikan nilai balik. Pada kedua kasus, x menjadi bernilai 11. Perbedaannya adalah apa yang menjadi nilai balik dari operasi.

Ada beberapa kentungan yang didapatkan ketika menggunakan operasi inkremen dan dekremen. Perhatikan program berikut, yang menghasilkan sebuah deret angka:

// Demonstrasi perbedaan antara format prefiks
// dan format postfiks dari ++.
using System;

class DemoPrePost {
  static void Main() {
    int x, y;
    int i;
   
    x = 1;
    y = 0;
    Console.WriteLine("Deret yang dihasilkan menggunakan y = y + x++;");
    for(i = 0; i < 10; i++) {
      y = y + x++; // postfiks ++

      Console.WriteLine(y + " ");
    }

    Console.WriteLine();

    x = 1;
    y = 0;
    Console.WriteLine("Deret yang dihasilkan menggunakan y = y + ++x;");
    for (i = 0; i < 10; i++) {
      y = y + ++x; // prefiks ++
      Console.WriteLine(y + " ");
    }
    Console.WriteLine();
  }
}

Keluaran program ditampilkan di sini:

Deret yang dihasilkan menggunakan y = y + x++;
1
3
6
10
15
21
28
36
45
55

Deret yang dihasilkan menggunakan y = y + ++x;
2
5
9
14
20
27
35
44
54
65

Seperti yang ditegaskan oleh keluaran, statemen

y = y + x++;

menambahkan nilai sekarang dari x dan y, dan menugaskan hasilnya kembali kepada y. Nilai dari x diinkremen setelah nilainya didapatkan. Namun, statemen

y = y + ++x;

memperoleh nilai dari x, menginkremen x, dan kemudian menambahkan nilai tersebut pada nilai sekarang dari y. Seperti ditunjukkan keluaran program, pengubahan ++x dan x++ mengubah deret secara substansial.


Operator Relasional dan Logikal
Istilah relasional berarti relasi antara nilai-nilai satu sama lain dan istilah logikal berarti cara dimana nilai true dan false dapat dihubungkan bersama. Karena operator relasional menghasilkan true atau false, operator ini seringkali bekerja dengan operator logikal. Karena alasan ini, kedua operator dibahas secara bersamaan di sini.

Operator-operator relasional adalah sebagai berikut:

Operator
Arti
==
Sama dengan
!=
Tidak sama dengan
< 
Lebih kecil dari
> 
Lebih besar dari
<=
Lebih kecil dari atau sama dengan
>=
Lebih besar dari atau sama dengan


Operator-operator logikal adalah sebagai berikut:

Operator
Arti
&
AND
|
OR
^
XOR (exclusive OR)
||
OR hubung-singkat
&&
AND hubung-singkat
!
NOT

Keluaran dari operator relasional dan operator logikal adalah sebuah nilai bool.

Secara umum, objek dapat dibandingkan ekualitas atau inekualitasnya menggunakan == dan !=. Namun, operator perbandingan, <, >, <=, atau >=, dapat dipakai hanya pada beberapa tipe yang mendukung relasi pengurutan. Oleh karena itu, semua operator relasional dapat diterapkan pada semua tipe numerik. Nilai bertipe bool hanya dapat dibandingkan ekualitas atau inekualitasnya karena nilai true dan false tidak dapat diurutkan. Sebagai contoh, true > false tidak ada maknanya dalam C#.

Untuk operator logikal, operand harus bertipe bool, dan hasil dari suatu operasi logikal juga bertipe bool. Operator logikal, &, |, ^, dan !, mendukung operasi logikal dasar AND, OR, XOR, dan NOT, sesuai dengan tabel kebenaran berikut:



Seperti yang ditunjukkan pada tabel, keluaran dari operasi XOR bernilai true ketika satu dan hanya satu operand bernilai true. Berikut adalah sebuah program yang mendemonstrasikan beberapa operator relasional dan logikal:

// Demonstrasi operator relasional dan logikal.
using System;

class OpRelLog {
    static void Main() {
        int i, j;
        bool b1, b2;
        i = 10;
        j = 11;

        if (i < j) Console.WriteLine("i < j");
        if (i <= j) Console.WriteLine("i <= j");
        if (i != j) Console.WriteLine("i != j");
        if (i == j) Console.WriteLine("ini tidak akan dieksekusi");
        if (i >= j) Console.WriteLine("ini tidak akan dieksekusi");
        if (i > j) Console.WriteLine("ini tidak akan dieksekusi");

        b1 = true;
        b2 = false;
        if (b1 & b2) Console.WriteLine("ini tidak akan dieksekusi");
        if (!(b1 & b2)) Console.WriteLine("!(b1 & b2) bernilai true");
        if (b1 | b2) Console.WriteLine("b1 | b2 bernilai true");
        if (b1 ^ b2) Console.WriteLine("b1 ^ b2 bernilai true");
    }
}

Keluaran program ditampilkan di sini:

i < j
i <= j
i != j
!(b1 & b2) bernilai true
b1 | b2 bernilai true
b1 ^ b2 bernilai true

Operator-operator logikal yang disediakan oleh C# mampu melakukan semua operasi logikal yang umum dijumpai. Namun, terdapat beberapa operasi lain yang dibentuk dengan aturan logika formal.  Operasi lain ini dapat dibangun menggunakan beberapa operator logikal yang didukung oleh C#. Jadi,  semua operator logikal yang disediakan C# bisa dimanfaatkan untuk membangun sembarang operasi logikal. Sebagai contoh, operasi logikal lain tersebut adalah implikasi. Implikasi merupakan sebuah operasi biner dimana keluaran bernilai false hanya jika operand kirinya bernilai true dan operand kanannya bernilai false. (Operasi implikasi merefleksikan ide bahwa kebenaran tidak bisa mengimplikasikan kesalahan). Tabel kebenaran operator implikasi ditampilkan di sini:



Operasi implikasi dapat dikonstruksi menggunakan kombinasi dari ! dan |, seperti ditampilkan di sini:

!p | q

Program berikut mengimplementasikan operasi implikasi:

// menciptakan operator implikasi dalam C#.
using System;

class Implikasi {
    static void Main() {
        bool p = false, q = false;
        int i, j;

        for (i = 0; i < 2; i++)
        {
            for (j = 0; j < 2; j++)
            {
                if (i == 0) p = true;
                if (i == 1) p = false;
                if (j == 0) q = true;
                if (j == 1) q = false;

                Console.WriteLine("p bernilai " + p + ", q bernilai " + q);
                if (!p | q) Console.WriteLine(p + " mengimplikasikan bahwa " + q +
                                             " bernilai " + true);
                Console.WriteLine();
            }
        }
    }
}

Keluaran ditampilkan di sini:

p bernilai True, q bernilai True
True mengimplikasikan bahwa True bernilai True

p bernilai True, q bernilai False

p bernilai False, q bernilai True
False mengimplikasikan bahwa True bernilai True

p bernilai False, q bernilai False
False mengimplikasikan bahwa False bernilai True


Operator Logikal Hubung-Singkat
C# menyediakan versi hubung-singkat dari operator logikal AND dan OR yang bisa dipakai untuk menghasilkan kode yang lebih efisien. Untuk memahami mengapa, perhatikan gagasan berikut. Dalam suatu operasi AND, jika operand pertamanya bernilai false, maka keluarannya bernilai false tidak memandang apa nilai yang dimiliki oleh operand kedua. Dalam suatu operasi OR, jika operand pertamanya bernilai true, maka keluarannya bernilai true tanpa memandang apa nilai yang dimiliki oleh operand keduanya. Jadi, pada kedua kasus tersebut, tidak diperlukan evaluasi terhadap operand kedua. Dengan tidak mengevaluasi operand kedua, waktu komputasi akan lebih hemat dan kode akan lebih efisien.

Operator AND hubung-singkat adalah && dan operator OR hubung singkat adalah ||. Seperti yang telah dijelaskan, operator AND dan OR normal adalah & dan |. Satu-satunya perbedaan antara versi normal dan versi hubung-singkat adalah bahwa setiap operand kedua selalu dievaluasi, tetap pada versi hubung-singkat, evaluasi terhadap operand kedua akan dilakukan hanya bila diperlukan.

Berikut adalah sebuah program yang mendemonstrasikan operator AND hubung-singkat. Program menentukan apakah nilai di dalam d adalah faktor dari n. Ini dilakukan dengan melakukan operasi modulus. Jika sisa pembagian dari n/d bernilai nol, maka d adalah faktor dari n. Tetapi, karena operasi modulus melibatkan pembagian, versi hubung-singkat dari AND dipakai untuk mencegah error pembagian-oleh-nol.

// Demonstrasi operator hubung-singkat.
using System;

class OpHubSingkat {
    static void Main() {
        int n, d;
       
        n = 10;
        d = 2;
        if (d != 0 && (n % d) == 0)
            Console.WriteLine(d + " adalah faktor dari " + n);
       
        d = 0; // sekarang, tetapkan d menjadi nol
       
        // karena d bernilai nol, maka operand kedua tidak dievaluasi.
        if (d != 0 && (n % d) == 0)
            Console.WriteLine(d + " adalah faktor dari " + n);
       
        // sekarang, coba hal yang sama tanpa operator hubung-singkat.
        // ini akan menyebabkan error pembagian-oleh-nol.
        if (d != 0 & (n % d) == 0)
            Console.WriteLine(d + " adalah faktor dari " + n);
    }
}

Untuk mencegah error pembagian-dengan-nol, statemen if terlebih dahulu memeriksa apakah d sama dengan nol. Jika ya, maka AND hubung-singkat akan berhenti pada titik tersebut dan tidak melakukan operasi modulus. Jadi, dalam pengujian pertama, d bernilai 2 dan operasi modulus dilakukan. Pengujian kedua gagal karena d ditetapkan menjadi nol, dan operasi modulus dilompati, menghindari error pembagian-oleh-nol. Terakhir, operator AND normal diuji-coba. Ini menyebabkan kedua operand dievaluasi, yang menyebabkan error runtime ketika error pembagian-oleh-nol terjadi.

Karena operator hubung-singkat, pada beberapa kasus, lebih efisien dari versi normalnya, Anda mungkin masih bertanya-tanya mengapa C# masih menawarkan operator AND dan OR versi normal. Jawabannya adalah bahwa dalam beberapa kasus Anda ingin kedua operand dari operasi AND atau OR dievaluasi. Perhatikan program berikut:

// Efek samping bisa berguna.
using System;

class EfekSamping {
    static void Main() {
        int i;
        bool suatuKondisi = false;
        i = 0;
      
        // Di sini, i masih diinkremen meski if gagal.
        if (suatuKondisi & (++i < 100))
            Console.WriteLine("ini tidak akan ditampilkan");
        Console.WriteLine("statemen if dieksekusi: " + i); // menampilkan 1
       
        // Pada kasus ini, i tidak diinkremen karena operator
        // hubung-singkat melompati inkremen.
        if (suatuKondisi && (++i < 100))
            Console.WriteLine("ini tidak akan ditampilkan");
        Console.WriteLine("statemen if dieksekusi: " + i); // masih 1 !!
    }
}

statemen if dieksekusi: 1
statemen if dieksekusi: 1

Pertama, perhatikan bahwa variabel suatuKondisi bertipe bool diinisialisasi dengan false. Selanjutnya, setiap statemen if diperiksa. Seperti yang diindikasikan komentar, dalam statemen if pertama, i diinkremen meskipun fakta bahwa suatuKondisi bernilai false. Ketika operator & digunakan, seperti dalam statemen if pertama, ekspresi pada sisi kanan operator & tetap dievaluasi tanpa memandang nilai ekspresi kiri. Tetapi, dalam statemen if kedua, operator hubung-singkat digunakan. Pada kasus ini, variabel i tidak diinkremen karena operand kiri, suatuKondisi, bernilai false, yang menyebabkan ekspresi di sebelah kanan dilompati. Pelajaran di sini adalah bahwa jika kode Anda mengharapkan operand sisi-kanan dari operasi AND atau OR dievaluasi, maka Anda harus menggunakan versi normal dari operasi AND atau OR.

Satu hal penting lain: AND hubung-singkat juga dikenal dengan AND kondisional, dan OR hubung-singkat juga dikenal dengan OR kondisional.


Operator Penugasan
Operator penugasan adalah tanda sama dengan tunggal, =. Operator penugasan dalam C# sama seperti bahasa pemrograman lainnya. Bentuk umumnya adalah:

nama-var = ekspresi;

Di sini, tipe dari nama-var harus kompatibel dengan tipe dari ekspresi.

Operator penugasan mempunyai satu sifat penting: penugasan berantai. Sebagai contoh, perhatikan fragmen kode berikut:

int x, y, z;
x = y = z = 100; // menetapkan x, y, dan z menjadi 100

Fragmen ini menetapkan variabel x, y, dan z menjadi 100 menggunakan satu statemen tunggal. Ini diperbolehkan karena = adalah sebuah operator yang menghasilkan nilai yang ditugaskan. Jadi, nilai dari z = 100 adalah 100, yang kemudian ditugaskan kepada y, yang seterusnya ditugaskan kepada x. Penggunaan penugasan berantai merupakan cara mudah dalam menetapkan nilai sama atas sekelompok variabel.


Penugasan Gabungan
C# menyediakan beberapa operator penugasan gabungan yang dapat dipakai untuk menyederhanakan pengkodean statemen penugasan tertentu. Akan diberikan sebuah contoh. Statemen penugasan yang ditunjukkan di sini:

x = x + 10;

dapat dituliskan menggunakan statemen penugasan sebagai

x += 10;

Pasangan operator += memberitahu kompiler untuk menugaskan nilai x yang ditambah 10 kepada x. Berikut contoh lain. Statemen

x = x - 100;

sama dengan

x -= 100;

Kedua statemen tersebut menugaskan x yang dikurangi dengan 100 kepada x.

Ada beberapa operator penugasan gabungan untuk operator biner (operator yang memerlukan dua operand). Bentuk umum penugasan gabungan adalah

nama-var op= ekspresi;

Semua operator penugasan aritmatik dan logikal diberikan di sini:


Operator penugasan gabungan mempunyai dua keuntungan. Pertama, operator penugasan gabungan lebih kompak/pendek. Kedua, operator penugasan gabungan bisa menghasilkan kode yang lebih efisien (karena operand sisi-kiri hanya dievaluasi sekali). Karena alasan ini, Anda akan sering melihat pemakaian operator penugasan gabungan di dalam banyak program C# yang ditulis secara profesional.


Operator Bitwise
C# menyediakan himpunan operator bitwise yang memampukan C# menyelesaikan berbagai masalah yang lebih luas. Operator bitwise hanya didefinisikan untuk operand integer. Operator bitwise tidak bisa diterapkan pada bool, float, atau double. Operator ini dikatakan operator bitwise karena dipakai untuk menguji, menetapkan, atau menggeser bit-bit dari suatu nilai integer. Di antara berbagai kegunaannya, operasi bitwise penting dalam tugas-tugas pemrograman level-sistem, seperti dalam menganalisa informasi status dari sebuah divais.

Operator AND, OR, XOR, dan NOT
Operator bitwise AND, OR, XOR, dan NOT adalah &, |, ^, dan ~. Semua operator ini ekivalen dengan logika Boolean. Tabel berikut menunjukkan keluaran dari setiap operasi menggunakan bit 1 dan 0:



Dalam kegunaan yang umum dijumpai, Anda bisa berpikir bahwa AND bitwise adalah sebagai sebuah mekanisme untuk menon-aktif-kan bit. Yaitu, sembarang bit yang bernilai 0 pada salah satu operand akan menyebabkan bit keluaran menjadi 0. Sebagai contoh,

   1 1 0 1   0 0 1 1
&  1 0 1 0   1 0 1 0
   1 0 0 0   0 0 1 0

Operator
Hasil
&
AND bitwise
|
OR bitwise
^
XOR bitwise
>> 
Geser kanan
<< 
Geser kiri
~
Komplemen satu

Gambar 3.1 Operator bitwise

Program berikut mendemonstrasikan & dengan menggunakannya untuk mengkonversi angka ganjil menjadi angka genap. Program melakukannya dengan menon-aktif-kan bit paling kurang signifikan (LSB, least significant bit). Sebagai contoh, angka 9 dalam bit adalah 0000  1001. Ketika bit LSB di-non-aktif-kan, angka ini menjadi 8 atau 0000  1000 dalam biner.

// Menggunakan AND bitwise untuk membuat angka genap.
using System;

class MembuatGenap {
    static void Main() {
        ushort angka;
        ushort i;

        for (i = 1; i <= 10; i++)
        {
            angka = i;

            Console.WriteLine("angka: " + angka);

            angka = (ushort)(angka & 0xFFFE);

            Console.WriteLine("angka setelah menon-aktif-kan bit LSB: "
                               + angka + "\n");
        }
    }
}

Keluaran program ditunjukkan di sini:

angka: 1
angka setelah menon-aktif-kan bit LSB: 0

angka: 2
angka setelah menon-aktif-kan bit LSB: 2

angka: 3
angka setelah menon-aktif-kan bit LSB: 2

angka: 4
angka setelah menon-aktif-kan bit LSB: 4

angka: 5
angka setelah menon-aktif-kan bit LSB: 4

angka: 6
angka setelah menon-aktif-kan bit LSB: 6

angka: 7
angka setelah menon-aktif-kan bit LSB: 6

angka: 8
angka setelah menon-aktif-kan bit LSB: 8

angka: 9
angka setelah menon-aktif-kan bit LSB: 8

angka: 10
angka setelah menon-aktif-kan bit LSB: 10

Nilai 0xFFFE yang dipakai dalam statemen AND adalah representasi heksadesimal dari 1111  1111  1111  1110. Oleh karena itu, operasi AND tidak mengubah semua bit dalam angka kecuali pada bit LSB, yang ditetapkan menjadi 0. Jadi, angka genap tidak berubah, dan angka ganjil dibuat genap dengan mengurangi nilainya sebesar 1.

Operator AND juga berguna ketika Anda ingin menentukan apakah sebuah bit on atau off. Sebagai contoh program ini mendemonstrasikan apakah suatu angka ganjil atau tidak.

// Menggunakan AND bitwise untuk menentukan jika sebuah angka ganjil.
using System;

class ApaGanjil {
    static void Main() {
        ushort angka;

        angka = 10;

        if ((angka & 1) == 1)
            Console.WriteLine("Ini tidak ditampilkan.");

        angka = 11;
        if ((angka & 1) == 1)
            Console.WriteLine(angka + " adalah angka ganjil.");
    }
}

Keluaran program ditampilkan di sini:

11 adalah angka ganjil.

Dalam statemen if, nilai dari angka diANDkan dengan 1. Jika bit LSB dalam angka bernilai 1, maka hasil dari angka & 1 adalah 1; sebaliknya, hasilnya adalah 0. Oleh karena itu, tubuh statemen if dieksekusi hanya jika angka genap.

Anda dapat memakai kapasitas pengujian-bit dari AND bitwise & untuk menciptakan sebuah program yang menggunakan & dalam menampilkan bit-bit sebuah nilai byte dalam format biner. Berikut adalah salah satu pendekatan yang bisa dilakukan:

// Menampilkan bit-bit dalam sebuah byte.
using System;

class TampilBit {
  static void Main() {
    int t;
    byte nil;

    nil = 123;
    for(t=128; t > 0; t = t/2) {
      if((nil & t) != 0) Console.Write("1 ");
      if ((nil & t) == 0) Console.Write("0 ");
    }
  }
}

Keluaran program ditampilkan di sini:

0 1 1 1 1 0 1 1

Loop for secara berurutan menguji setiap bit di dalam nil, menggunakan AND bitwise, untuk menentukan apakah bit 1 atau bit 0. Jika bit bernilai 1, maka dijit 1 ditampilkan; sebaliknya, dijit 0 ditampilkan.

OR bitwise dapat dipakai untuk mengaktifkan (menetapkan bit menjadi 1). Bit 1 dalam salah satu operand akan menyebabkan hasil dari operasi OR bitwise menjadi 1. Sebagai contoh

   1 1 0 1   0 0 1 1
|  1 0 1 0   1 0 1 0
   1 1 1 1   1 0 1 1

Anda dapat memanfaatkan OR untuk mengubah program pembuat-genap yang ditujukkan sebelumnya menjadi program pembuat-ganjil, yang ditampilkan di sini:
// Menggunakan OR bitwise untuk membuat sebuah angka menjadi ganjil.
using System;

class MembuatGanjil {
    static void Main() {
        ushort angka;
        ushort i;

        for (i = 1; i <= 10; i++)
        {
            angka = i;
            Console.WriteLine("angka: " + angka);

            angka = (ushort)(angka | 1);
            Console.WriteLine("angka setelah mengaktifkan bit LSB: "
                               + angka + "\n");
        }
    }
}

angka: 1
angka setelah mengaktifkan bit LSB: 1

angka: 2
angka setelah mengaktifkan bit LSB: 3

angka: 3
angka setelah mengaktifkan bit LSB: 3

angka: 4
angka setelah mengaktifkan bit LSB: 5

angka: 5
angka setelah mengaktifkan bit LSB: 5

angka: 6
angka setelah mengaktifkan bit LSB: 7

angka: 7
angka setelah mengaktifkan bit LSB: 7

angka: 8
angka setelah mengaktifkan bit LSB: 9

angka: 9
angka setelah mengaktifkan bit LSB: 9

angka: 10
angka setelah mengaktifkan bit LSB: 11

Program bekerja dengan mengORkan setiap angka denga nilai 1 karena 1 adalah nilai yang menghasilkan sebuah nilai dalam biner dimana di dalamnya hanya bit LSB ditetapkan menjadi 1. Ketika nilai ini diORkan dengan sembarang nilai lain, ia menghasilkan sebuah hasil dimana di dalamnya bit LSB dijadikan 1 dan semua bit lain dibiarkan tidak berubah. Jadi nilai genap akan ditambahkan 1, menjadi ganjil.

Operasi XOR (exclusive OR) akan menetapkan bit menjadi 1 jika dan hanya jika bit-bit yang sedang dibandingkan berbeda polaritas, seperti diilustrasikan di sini:

   0 1 1 1   1 1 1 1
^  1 0 1 1   1 0 1 1
   1 1 0 0   0 1 0 0

Operator XOR mempunyai watak menarik yang bermanfaat pada beberapa situasi. Ketika suatu nilai X diXORkan dengan nilai lain Y, dan kemudian hasilnya diXORkan dengan Y kembali, maka akan dihasilkan X lagi. Yaitu, diberikan runtun

R1 = X ^ Y;
R2 = R1 ^ Y;

R2 bernilai sama dengan X. Jadi, keluaran dari sebuah runtun dua XOR menggunakan nilai yang sama akan menghasilkan nilai semula. Fitur XOR ini dapat diterapkan untuk menciptakan cipher sederhana dimana di dalamnya suatu integer berperan sebagai kunci yang bisa dipakai untuk mengkodekan dan mendekodekan sebuah pesan dengan mengXORkan karakter-karakter di dalam pesan tersebut. Untuk mengkodekan operasi XOR diterapkan pertama kali, menghasilkan cipherteks. Untuk mendekodekan, XOR diterapkan kedua kalinya, menghasilkan plainteks. Tentu saja, cipher semacam ini tidak memiliki peranan praktis, karena terlalu sederhana untuk dipecahkan. Namun, contoh tersebut mengilustrasikan cara yang menarik dalam mendemonstrasikan pengaruh XOR, seperti ditunjukkan program berikut:

// Demonstrasi XOR.
using System;

class Enkode {
    static void Main() {
        char ch1 = 'B';
        char ch2 = 'A';
        char ch3 = 'H';
        int kunci = 88;

        Console.WriteLine("Pesan asli: " + ch1 + ch2 + ch3);

        // Mengkodekan pesan.
        ch1 = (char)(ch1 ^ kunci);
        ch2 = (char)(ch2 ^ kunci);
        ch3 = (char)(ch3 ^ kunci);

        Console.WriteLine("Pesan terkode: " + ch1 + ch2 + ch3);

        // Mendekodekan pesan.
        ch1 = (char)(ch1 ^ kunci);
        ch2 = (char)(ch2 ^ kunci);
        ch3 = (char)(ch3 ^ kunci);

        Console.WriteLine("Pesan terdekode: " + ch1 + ch2 + ch3);
    }
}

Keluaran program ditampilkan di sini:

Pesan asli: BAH
Pesan terkode: →↓►
Pesan terdekode: BAH

Seperti yang dapat Anda lihat, hasil dari dua XOR menggunakan kunci yang sama menghasilkan pesan terdekode. (Ingat, cipher XOR sederhana tidak cocok untuk dunia nyata, karena tidak aman).

Operator komplemen satu (NOT) membalikkan keadaan semua bit dari operandnya. Sebagai contoh, jika suatu integer A memiliki pola bit 1001  0110, maka ~A menghasilkan pola bit 0110  1001.

Program berikut mendemonstrasikan operator NOT dengan menampilkan sebuah angka dan komplemennya dalam biner:

// Demonstrasi NOT bitwise.
using System;

class DemoNt {
  static void Main() {
    sbyte b = -34;

    for(int t=128; t > 0; t = t/2) {
      if((b & t) != 0) Console.Write("1 ");
      if((b & t) == 0) Console.Write("0 ");
    }

    Console.WriteLine();

    // membalikkan semua bit
    b = (sbyte)~b;
    for (int t = 128; t > 0; t = t / 2)
    {
      if ((b & t) != 0) Console.Write("1 ");
      if ((b & t) == 0) Console.Write("0 ");
    }
  }
}

Keluaran program ditampilkan di sini:

1 1 0 1 1 1 1 0
0 0 1 0 0 0 0 1


Operator Geser
Dalam C#, adalah memungkinkan untuk menggeser bit-bit yang membentuk sebuah nilai integer ke kiri atau ke kanan sejauh sejumlah posisi tertentu. C# mendefinisikan dua operasi penggeseran-bit yang ditunjukkan di sini:

<< 
Geser kiri
>> 
Geser kanan


Bentuk umum dari kedua operator tersebut ditampilkan di sini:

nilai << jumlah-bit
nilai >> jumlah-bit

Di sini, nilai adalah nilai yang sedang digeser sejauh sejumlah posisi bit yang ditentukan oleh jumlah-bit. Operasi geser-kiri menyebabkan semua bit di dalam nilai tertentu digeser ke kiri sejauh satu posisi dan sebuah bit nol ditempatkan di sisi kanan. Operasi geser-kanan menyebabkan semua bit di dalam nilai tertentu digeser ke kanan sejauh satu posisi. Pada kasus penggeseran kanan atas nilai tak-bertanda, sebuah bit 0 ditempatkan di sisi kiri. Pada kasus penggeseran kanan atas nilai bertanda, tanda bit dipertahankan. Ingat bahwa angka negatif direpresentasikan dengan menetapkan bit paling signifikan (MSB, most significant bit) dari suatu integer menjadi 1. Jadi, jika nilai yang sedang digeser adalah negatif, maka setiap penggeseran ke kanan akan menempatkan bit 1 di sisi kiri. Jika nilai yang sedang digeser adalah positif, maka setiap penggeseran ke kanan akan menempatkan bit 0 di sisi kiri. Untuk kedua operasi geser kiri dan geser kanan, semua bit yang digeser menjadi hilang.

Berikut adalah sebuah program yang secara grafikal mengilustrasikan pengaruh operasi geser kiri dan geser kanan. Di sini, sebuah integer diberikan nilai awal 1, yang berarti bahwa bit LSB ditetapkan menjadi 1. Kemudian, penggeseran sebanyak delapan kali dilakukan pada integer tersebut. Setelah tiap pergeseran, delapan bit terendah dari nilai tersebut akan ditampilkan. Proses akan diulangi kecuali bila sebuah bit 1 ditempatkan pada posisi bit ke delapan, dan penggeseran ke kanan dilakukan.

// Demonstrasi operator geser << dan >>.
using System;

class DemoGeser {
  static void Main() {
    int nil = 1;

    for (int i = 0; i < 8; i++)
    {
      for (int t = 128; t > 0; t = t / 2)
      {
          if ((nil & t) != 0) Console.Write("1 ");
          if ((nil & t) == 0) Console.Write("0 ");
      }
      Console.WriteLine();
      nil = nil << 1; // geser kiri
    }

    Console.WriteLine();
    nil = 128;
    for (int i = 0; i < 8; i++)
    {
      for (int t = 128; t > 0; t = t / 2)
      {
          if ((nil & t) != 0) Console.Write("1 ");
          if ((nil & t) == 0) Console.Write("0 ");
      }
      Console.WriteLine();
      nil = nil >> 1; // geser kanan
    }
  }
}

Keluaran program ditampilkan di sini:

0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0

1 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 1

Karena biner merupakan bilangan berbasis 2, operator penggeseran dapat dipakai sebagai sebuah cara untuk membagi atau mengalikan sebuah integer dengan 2. Penggeseran ke kiri akan menggandakan sebuah nilai. Penggeseran ke kanan akan membuat nilai menjadi setengahnya. Berikut adalah sebuah contoh yang perlu disimak:

// Menggunakan operator penggeseran untuk mengalikan dan membagi dengan 2.
using System;

class KaliBagi {
  static void Main() {
    int n;
   
    n = 10;
    Console.WriteLine("Nilai dari n: " + n);

    // Mengalikan dengan 2.
    n = n << 1;
    Console.WriteLine("Nilai dari n setelah n = n * 2: " + n);

    // Mengalikan dengan 4.
    n = n << 2;
    Console.WriteLine("Nilai dari n setelah n = n * 4: " + n);

    // Membagi dengan 2.
    n = n >> 1;
    Console.WriteLine("Nilai dari n setelah n = n / 2: " + n);

    // Membagi dengan 4.
    n = n >> 2;
    Console.WriteLine("Nilai dari n setelah n = n / 4: " + n);
    Console.WriteLine();

    // Reset n.
    n = 10;
    Console.WriteLine("Nilai dari n: " + n);

    // Mengalikan dengan 2, 30 kali.
    n = n << 30; // data hilang
    Console.WriteLine("Nilai dari n setelah penggeseran 30 posisi: " + n);
  }
}

Keluaran program ditunjukkan di sini:

Nilai dari n: 10
Nilai dari n setelah n = n * 2: 20
Nilai dari n setelah n = n * 4: 80
Nilai dari n setelah n = n / 2: 40
Value of n after n = n / 4: 10

Nilai dari n: 10
Nilai dari n setelah penggeseran 30 posisi: -2147483648

Perhatikan baris terakhir pada keluaran. Ketika nilai 10 digeser ke kiri sebanyak 30 kali, informasi hilang karena bit-bit digeser ke luar rentang dari sebuah int. Pada kasus ini, nilai sampah yang dihasilkan bernilai negatif karena sebuah bit 1 ditempatkan pada bit MSB, yang digunakan sebagai bit tanda, menyebabkan angka diinterpretasikan sebagai nilai negatif. Ini mengilustrasikan mengapa Anda harus berhati-hati ketika menggunakan operator penggeseran dalam mengalikan atau membagi sebuah nilai dengan 2.


Operator ?
Salah satu operator yang paling menakjubkan dalam C# adalah operator ?, yang merupakan operator kondisional C#. Operator ? seringkali dipakai untuk menggantikan konstruksi if...else.  Operator ini mempunyai bentuk umum:

Eksp1 ? Ekps2: Eksp3

dimana Eksp2 merupakan sebuah ekspresi bool, dan Eksp2 dan Eksp2 adalah ekspresi biasa. Tipe Eksp2 dan Eksp3 harus sama (atau, konversi implisit akan terjadi). Perhatikan penggunaan dan penempatan tanda titik-dua.

Nilai dari sebuah ekspresi ? ditentukan seperti ini: Eksp1 dievaluasi. Jika bernilai true, maka Eksp2 akan dievaluasi dan menjadi nilai dari keseluruhan ekspresi ?. Jika bernilai false, maka Eksp3 akan dievaluasi dan menjadi nilai dari keseluruhan ekspresi ?. Perhatikan contoh ini, yang menugaskan nilai absolut absnil:

absnil = nil < 0 ? -nil : nil; // ,mendapatkan nilai absolut dari nil

Di sini, absnil akan ditugasi nilai dari nil jika nil bernilai nol atau lebih besar. Jika nil bernilai negatif, maka absnil akan ditugasi nilai negatif dari nilai tersebut (yang akan menghasilkan sebuah nilai positif). Berikut disajikan sebuah contoh operator ?. Program ini membagi dua angka, tetapi tidak mengijinkan pembagian oleh nol.

// Mencegah pembagian oleh nol menggunakan ?.
using System;

class JgnBagiNol {
    static void Main() {
        int hasil;

        for (int i = -5; i < 6; i++)
        {
            hasil = i != 0 ? 100 / i : 0;
            if (i != 0)
                Console.WriteLine("100 / " + i + " adalah " + hasil);
        }
    }
}

Keluaran program ditunjukkan di sini:

100 / -5 adalah -20
100 / -4 adalah -25
100 / -3 adalah -33
100 / -2 adalah -50
100 / -1 adalah -100
100 / 1 adalah 100
100 / 2 adalah 50
100 / 3 adalah 33
100 / 4 adalah 25
100 / 5 adalah 20

Anda perlu memperhatikan baris ini di dalam program:

hasil = i != 0 ? 100 / i : 0;

Di sini, hasil ditugasi nilai keluaran dari pembagian 100 oleh i. Namun, pembagian ini terjadi hanya jika i tidak bernilai 0. Ketika i bernilai 0,  maka nilai 0 ditugaskan kepada hasil. Berikut disajikan contoh lainnya, dimana program yang diberikan menampilkan hasil pembagian 100 hanya oleh angka genap tak-nol:

// Membagi hanya dengan angka genap, tak-nol.
using System;

class NoZeroDiv2 {
    static void Main() {
        for (int i = -5; i < 6; i++)
            if (i != 0 ? (i % 2 == 0) : false)
                Console.WriteLine("100 / " + i + " adalah " + 100 / i);
    }
}

Keluaran program ditampilkan di sini:

100 / -4 adalah -25
100 / -2 adalah -50
100 / 2 adalah 50

100 / 4 adalah 25



No comments:

Post a Comment