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 operator | Operator |
|---|---|
| logika | and, 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.
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;# kompilasi program dengan operator short-circuit
gnatmake -q sirkuit_pendek.adb
# jalankan program
./sirkuit_pendekselesai tanpa exceptionNilai 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.
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;# kompilasi lalu jalankan program dengan operator biasa
gnatmake -q pembagi_nol.adb
./pembagi_nolpembagi_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 zeroDengan 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.
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;# kompilasi program
gnatmake -q rem_mod.adb
# jalankan program
./rem_mod 7 rem 3 = 1 mod = 1
-7 rem 3 = -1 mod = 2
7 rem -3 = 1 mod = -2
-7 rem -3 = -1 mod = -1Baris 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
remmengikuti tanda pembilangnya sehingga dapat negatif. Gunakanmodapabila sisa nonnegatif diperlukan untuk penyebut positif. - Mencampur
anddanordalam satu ekspresi tanpa tanda kurung. Kompilator menolaknya dengan pesanmixed logical operators in expressionkarena pengelompokan yang dimaksud tidak pasti. Tambahkan tanda kurung pada setiap tingkat penggabungan yang berbeda. - Mengganti
and thendengananduntuk mempersingkat kode. Bentuk tanpa akhiran selalu mengevaluasi operan kanannya, dan operan kanan yang hanya sah setelah syarat lolos dapat menimbulkan exception. Pertahankanand thenpada uji yang operan kanannya sah hanya setelah syarat lolos.
Ringkasan#
- Presedensi operator mengelompokkan ekspresi secara pasti, dan pencampuran
anddenganortanpa tanda kurung ditolak kompilator. - Operator
and thendanor elsemengevaluasi operan kanannya hanya apabila diperlukan, sehingga operan yang berbahaya apabila dihitung dapat ditiadakan. - Hasil
remmengikuti tanda pembilang, sedangkan hasilmodmengikuti tanda penyebut, dan pembagian/memotong ke arah nol.
Referensi#
- 4.5 Operators and Expression Evaluation — Ada Reference Manual 2022 — Mendaftar kelas operator dan urutan presedensinya.
- 4.5.1 Logical Operators and Short-circuit Control Forms — Ada Reference Manual 2022
— Menetapkan semantik
and thendanor else. - 4.5.5 Multiplying Operators — Ada Reference Manual 2022
— Menetapkan definisi
remdanmodbeserta tanda hasilnya.