Ekspresi

Operator pada ekspresi Ada, bentuk evaluasi short-circuit, dan perbedaan rem dengan mod.

Daftar isi

Sebuah ekspresi menghitung nilai dari operan dan operator, dan bahasa menetapkan pengelompokannya secara presisi. Topik ini membahas kelas operator pada Ada beserta presedensinya, evaluasi short-circuit pada operator logika, dan dua operator sisa pembagian, yaitu rem dan mod. Setelah membacanya, gabungan operator dapat ditulis dengan pengelompokan yang pasti, dan perbedaan perilaku kedua operator sisa dapat dijelaskan dari tandanya.

Operator dan presedensi#

Operator pada Ada dikelompokkan menurut tingkat presedensi, mulai dari operator logika and, or, dan xor yang paling rendah, hingga abs, not, dan ** yang paling tinggi. Operator relasional =, /=, <, <=, >, dan >= berada di atas operator logika, sedangkan penjumlahan biner +, -, dan & lebih tinggi lagi daripada operator relasional. Tabel berikut merangkum urutan tersebut dari presedensi terendah ke tertinggi.

Kelas operatorOperator
logikaand, or, xor
relasional dan keanggotaan=, /=, <, <=, >, >=, in, not in
penjumlahan biner+, -, &
penjumlahan unar+, -
perkalian*, /, rem, mod
presedensi tertinggi**, abs, not

Presedensi menentukan pengelompokan operan, bukan urutan pengerjaan. Karena operator relasional lebih tinggi daripada operator logika, ekspresi X > 3 and X < 9 dikelompokkan sebagai dua perbandingan yang digabungkan tanpa memerlukan tanda kurung. Sebaliknya, and dan or sama tinggi presedensinya, sehingga gabungan keduanya dalam satu ekspresi tanpa tanda kurung ditolak kompilator dengan pesan mixed logical operators in expression. Tanda kurung tetap disarankan pada gabungan yang rentan salah baca, agar kelompok operasi sesuai maksud penulis.

Evaluasi short-circuit#

Bentuk and then dan or else mengevaluasi operan kanannya hanya apabila operan kiri belum menentukan hasil. Pada A and then B, operan B ditiadakan apabila A bernilai false, sedangkan pada A or else B, operan B ditiadakan apabila A bernilai true. Bentuk and dan or tanpa akhiran selalu mengevaluasi kedua operannya. Pembedaan ini menentukan apakah operan kanan yang hanya sah setelah syarat tertentu ikut dihitung.

ada sirkuit_pendek.adb
with Ada.Text_IO;

procedure Sirkuit_Pendek is
   Pembagi : Integer := 0;
begin
   if Pembagi /= 0 and then 100 / Pembagi > 10 then
      Ada.Text_IO.Put_Line ("cabang dijalankan");
   end if;
   Ada.Text_IO.Put_Line ("selesai tanpa exception");
end Sirkuit_Pendek;
bash
# kompilasi program dengan operator short-circuit
gnatmake -q sirkuit_pendek.adb
# jalankan program
./sirkuit_pendek
text Keluaran
selesai tanpa exception

Nilai Pembagi adalah nol, sehingga uji Pembagi /= 0 bernilai false dan operan kanan yang memuat pembagian tidak pernah dihitung. Program mencapai Put_Line terakhir tanpa exception. Pembagian dengan nol hanya dieksekusi apabila syaratnya lolos, dan syarat itu justru gagal pada data ini. Program berikut menggunakan and biasa pada percabangan yang sama.

ada pembagi_nol.adb
with Ada.Text_IO;

procedure Pembagi_Nol is
   Pembagi : Integer := 0;
begin
   if Pembagi /= 0 and 100 / Pembagi > 10 then
      Ada.Text_IO.Put_Line ("cabang dijalankan");
   end if;
   Ada.Text_IO.Put_Line ("tidak pernah dicapai");
end Pembagi_Nol;
bash
# kompilasi lalu jalankan program dengan operator biasa
gnatmake -q pembagi_nol.adb
./pembagi_nol
text Keluaran
pembagi_nol.adb:6:30: warning: division by zero [enabled by default]
pembagi_nol.adb:6:30: warning: Constraint_Error will be raised at run time [enabled by default]

raised CONSTRAINT_ERROR : pembagi_nol.adb:6 divide by zero

Dengan and biasa, kedua operan dihitung, sehingga pembagian dengan nol dieksekusi dan Constraint_Error dilempar dengan pesan pembagian nol (divide by zero). Peringatan waktu kompilasi bahkan telah menandai pembagian itu sebelum program dijalankan. Kedua program hanya berbeda pada satu kata, dan perbedaan satu kata itu menentukan apakah program berakhir normal atau berakhir dengan exception.

rem dan mod#

Operator rem dan mod sama-sama menghitung sisa pembagian dua bilangan bulat, tetapi tanda hasilnya berbeda. Hasil rem mengikuti tanda pembilangnya, sedangkan hasil mod mengikuti tanda penyebutnya. Kedua operator melayani kebutuhan yang berbeda: rem cocok untuk sisa pembagian aritmetika biasa, sedangkan mod cocok untuk perhitungan siklis seperti nomor hari dalam pekan, karena hasilnya selalu nonnegatif untuk penyebut positif. Program berikut menghitung keduanya untuk empat kombinasi tanda.

ada rem_mod.adb
with Ada.Text_IO;

procedure Rem_Mod is
   procedure Tampilkan (A, B : Integer) is
   begin
      Ada.Text_IO.Put_Line (Integer'Image (A) & " rem " & Integer'Image (B)
                            & " = " & Integer'Image (A rem B)
                            & "   mod = " & Integer'Image (A mod B));
   end Tampilkan;
begin
   Tampilkan (7, 3);
   Tampilkan (-7, 3);
   Tampilkan (7, -3);
   Tampilkan (-7, -3);
end Rem_Mod;
bash
# kompilasi program
gnatmake -q rem_mod.adb
# jalankan program
./rem_mod
text Keluaran
 7 rem  3 =  1   mod =  1
-7 rem  3 = -1   mod =  2
 7 rem -3 =  1   mod = -2
-7 rem -3 = -1   mod = -1

Baris pertama memuat dua bilangan positif sehingga kedua operator menghasilkan nilai yang sama. Baris kedua memperlihatkan perbedaannya: -7 rem 3 menghasilkan -1 karena tanda mengikuti pembilang, sedangkan -7 mod 3 menghasilkan 2 karena tanda mengikuti penyebut. Baris ketiga dan keempat menunjukkan pola yang sama untuk penyebut negatif. Pembagian bilangan bulat dengan / memotong ke arah nol, sehingga hasil bagi dikali penyebut ditambah hasil rem selalu mengembalikan pembilang semula.

Nilai mod untuk penyebut positif selalu berada dalam rentang 0 hingga penyebut dikurangi satu, sehingga cocok untuk indeks yang berputar. Nilai rem dapat negatif sesuai tanda pembilangnya, dan perbedaan ini sering muncul saat algoritma dari bahasa lain dipindahkan. Periksa kembali setiap terjemahan rumus yang memuat operasi sisa, karena bahasa yang berbeda memilih aturan tanda yang berbeda pula.

Kesalahan umum#

Tiga kekeliruan berikut sering muncul saat ekspresi logika dan aritmetika ditulis.

  • Mengasumsikan sisa pembagian selalu nonnegatif. Hasil rem mengikuti tanda pembilangnya sehingga dapat negatif. Gunakan mod apabila sisa nonnegatif diperlukan untuk penyebut positif.
  • Mencampur and dan or dalam satu ekspresi tanpa tanda kurung. Kompilator menolaknya dengan pesan mixed logical operators in expression karena pengelompokan yang dimaksud tidak pasti. Tambahkan tanda kurung pada setiap tingkat penggabungan yang berbeda.
  • Mengganti and then dengan and untuk mempersingkat kode. Bentuk tanpa akhiran selalu mengevaluasi operan kanannya, dan operan kanan yang hanya sah setelah syarat lolos dapat menimbulkan exception. Pertahankan and then pada uji yang operan kanannya sah hanya setelah syarat lolos.

Ringkasan#

  • Presedensi operator mengelompokkan ekspresi secara pasti, dan pencampuran and dengan or tanpa tanda kurung ditolak kompilator.
  • Operator and then dan or else mengevaluasi operan kanannya hanya apabila diperlukan, sehingga operan yang berbahaya apabila dihitung dapat ditiadakan.
  • Hasil rem mengikuti tanda pembilang, sedangkan hasil mod mengikuti tanda penyebut, dan pembagian / memotong ke arah nol.

Referensi#