Ekspresi dan prioritas

Operator aritmetika, relasional, dan logika beserta aturan prioritas dan konversi tipe pada ekspresi.

Daftar isi

Topik ini membahas operator aritmetika, relasional, dan logika pada Fortran beserta aturan prioritas yang menentukan urutan evaluasinya. Jebakan pembagian bilangan bulat dan konversi tipe pada ekspresi campuran dibahas dengan program yang dapat dijalankan. Setelah topik ini diselesaikan, nilai sebuah ekspresi dapat diprediksi tanpa harus menjalankan programnya terlebih dahulu.

Prioritas operator aritmetika#

Ekspresi aritmetika tersusun atas operator pangkat **, perkalian dan pembagian * serta /, dan penjumlahan serta pengurangan + dan -. Aturan prioritas (precedence) menetapkan bahwa pangkat dievaluasi lebih dahulu, kemudian kali dan bagi, lalu jumlah dan kurang. Tanda kurung mengubah urutan secara eksplisit dan dibaca lebih dahulu dibandingkan operator mana pun. Spasi di sekitar operator tidak memengaruhi hasil, tetapi penulisan yang konsisten memudahkan pembacaan.

Operator pangkat bersifat asosiatif ke kanan, artinya 2 ** 3 ** 2 dibaca 2 ** (3 ** 2). Dalam notasi matematika, ekspresi tersebut setara dengan 232=29=5122^{3^{2}} = 2^{9} = 512. Tanda minus tunggal (unary minus) berprioritas di bawah pangkat, sehingga -7 ** 2 dibaca -(7 ** 2) dan menghasilkan -49, bukan 49. Pangkat menerima operand integer maupun real, dan tipe hasilnya mengikuti tipe operand yang lebih umum, sehingga 2 ** 0.5 menghasilkan nilai akar dua dalam bentuk real.

fortran prioritas.f90
program prioritas
  implicit none

  integer :: a, b

  a = 7
  b = 2

  print *, "7 + 2 * 3         =", 7 + 2 * 3
  print *, "(7 + 2) * 3       =", (7 + 2) * 3
  print *, "2 ** 3 ** 2       =", 2 ** 3 ** 2
  print *, "-7 ** 2           =", -7 ** 2
  print *, "7 / 2             =", 7 / 2
  print *, "7 / 2.0           =", 7 / 2.0
  print *, "real(a) / real(b) =", real(a) / real(b)
end program prioritas
bash
# kompilasi program prioritas menjadi berkas executable bernama prioritas
gfortran prioritas.f90 -o prioritas
# jalankan program hasil kompilasi
./prioritas
text Keluaran
 7 + 2 * 3         =          13
 (7 + 2) * 3       =          27
 2 ** 3 ** 2       =         512
 -7 ** 2           =         -49
 7 / 2             =           3
 7 / 2.0           =   3.50000000
 real(a) / real(b) =   3.50000000

Empat baris pertama pada keluaran memperlihatkan peran prioritas, tanda kurung, dan asosiasi pangkat. Baris 7 / 2 menghasilkan 3, bukan 3.5, karena kedua operandnya bilangan bulat. Perilaku tersebut dibahas pada bagian berikutnya, sedangkan baris 7 / 2.0 menghasilkan 3.5 karena salah satu operandnya real.

Pembagian bilangan bulat dan konversi tipe#

Apabila kedua operand / bertipe integer, hasilnya juga integer dan bagian pecahannya dibuang, sehingga 7 / 2 menghasilkan 3. Sisa pembagiannya diperoleh melalui intrinsik mod(a, b), yang mengembalikan 1 untuk mod(7, 2). Konversi eksplisit dilakukan dengan intrinsik real() untuk mengubah nilai ke real, atau int() untuk membuang bagian pecahan sebuah real. Intrinsik int() memotong ke arah nol dan bukan membulatkan, sehingga int(7.9) menghasilkan 7.

Ekspresi campuran, yaitu ekspresi yang memuat lebih dari satu tipe, dievaluasi dengan mengonversi operand yang lebih sederhana ke tipe yang lebih umum, sehingga 7 / 2.0 diperlakukan seperti 7.0 / 2.0. Konversi otomatis ini berjalan tanpa peringatan, sehingga program yang memuat pembagian bulat yang tidak disengaja tetap dapat dikompilasi dan berjalan dengan angka yang keliru. Penulisan konversi eksplisit dengan real() karenanya dianjurkan pada setiap pembagian yang hasilnya memang seharusnya pecahan.

fortran rata_rata.f90
program rata_rata
  implicit none

  integer :: total_nilai, banyak_nilai
  real :: rerata

  total_nilai = 78 + 74 + 81
  banyak_nilai = 3

  rerata = total_nilai / banyak_nilai
  print *, "rata-rata salah:", rerata

  rerata = real(total_nilai) / real(banyak_nilai)
  print *, "rata-rata benar:", rerata
end program rata_rata
bash
# kompilasi program rata_rata menjadi berkas executable bernama rata_rata
gfortran rata_rata.f90 -o rata_rata
# jalankan program hasil kompilasi
./rata_rata
text Keluaran
 rata-rata salah:   77.0000000
 rata-rata benar:   77.6666641

Program di atas menghitung rata-rata tiga nilai ujian dengan dua cara. Total nilai 233 dibagi 3 pada aritmetika bulat menghasilkan 77, sehingga rata-rata pertama tercetak 77.0000000. Cara kedua mengonversi kedua operand dengan real() sebelum pembagian, sehingga rata-rata kedua menampilkan nilai yang benar. Hasilnya 77.6666641, bukan 77.6666667, karena real default hanya menyimpan sekitar enam digit signifikan.

Operator relasional dan logika#

Operator relasional membandingkan dua nilai dan menghasilkan logical, yaitu == (sama dengan), /= (tidak sama dengan), <, <=, >, dan >=. Bentuk lama bertitik seperti .lt. dan .eq. masih sah menurut standar, tetapi bentuk simbol lebih mudah dibaca. Operator logika menggabungkan nilai logical, yaitu .and. (dan), .or. (atau), .not. (negasi), serta .eqv. dan .neqv. untuk ekuivalensi. Operator .eqv. menghasilkan true apabila kedua operand sama, sedangkan .neqv. menghasilkan true apabila keduanya berbeda.

PrioritasOperatorKelompok
1**pangkat
2*, /kali dan bagi
3+, -jumlah dan kurang
4==, /=, <, <=, >, >=relasional
5.not.negasi logika
6.and.konjungsi logika
7.or.disjungsi logika
8.eqv., .neqv.ekuivalensi logika

Tabel di atas melengkapi aturan prioritas aritmetika yang dibahas pada bagian pertama. Karena operator relasional berprioritas lebih tinggi daripada operator logika, pernyataan nilai >= 75 .and. hadir dibaca (nilai >= 75) .and. hadir tanpa tanda kurung tambahan. Apabila ragu, tanda kurung tetap boleh ditambahkan karena tidak mengubah hasil dan membuat maksud lebih jelas.

Perbedaan dengan notasi matematika juga perlu dicermati. Ekspresi rentang seperti 0 <= nilai <= 100 tidak diperlakukan sebagai rentang ganda, karena compiler membacanya sebagai perbandingan bertingkat yang tidak sah dan menolaknya dengan pesan error saat kompilasi. Rentang semacam itu ditulis dengan dua perbandingan yang digabungkan, misalnya nilai >= 0 .and. nilai <= 100.

Standar Fortran 2008 dan seterusnya menjamin sifat short-circuit untuk .and. dan .or., yaitu operand kanan tidak dievaluasi apabila operand kiri sudah menentukan hasil akhirnya. Sifat ini dimanfaatkan dengan menempatkan syarat pengaman pada operand kiri, sehingga perhitungan yang berisiko pada operand kanan tidak pernah dijalankan tanpa pemeriksaan.

fortran
! tidak-dijalankan
! pemeriksaan pembagi di kiri menjamin pembagian hanya dilakukan
! pada pembagi yang bukan nol
if (pembagi /= 0.0 .and. bilangan / pembagi > 2.0) then
  print *, "memenuhi syarat"
end if
fortran logika.f90
program logika
  implicit none

  integer :: nilai
  logical :: hadir, tugas_lengkap

  nilai = 78
  hadir = .true.
  tugas_lengkap = .false.

  print *, "nilai >= 75      :", nilai >= 75
  print *, "nilai /= 100     :", nilai /= 100
  print *, "hadir            :", hadir
  print *, ".not. hadir      :", .not. hadir
  print *, "hadir .and. tugas:", hadir .and. tugas_lengkap
  print *, "hadir .or. tugas :", hadir .or. tugas_lengkap
  print *, "lulus syarat     :", nilai >= 75 .and. hadir
end program logika
bash
# kompilasi program logika menjadi berkas executable bernama logika
gfortran logika.f90 -o logika
# jalankan program hasil kompilasi
./logika
text Keluaran
 nilai >= 75      : T
 nilai /= 100     : T
 hadir            : T
 .not. hadir      : F
 hadir .and. tugas: F
 hadir .or. tugas : T
 lulus syarat     : T

Program di atas mengevaluasi satu rangkaian syarat kelulusan. Nilai 78 memenuhi perbandingan nilai >= 75, konstanta .true. dan .false. mengisi dua variabel logical, dan negasi .not. hadir menghasilkan F. Konjungsi hadir .and. tugas_lengkap menghasilkan F karena salah satu operandnya false, sedangkan disjungsi hadir .or. tugas_lengkap menghasilkan T. Baris terakhir menggabungkan relasional dan logika dalam satu ekspresi tanpa tanda kurung, dan hasilnya tetap benar karena aturan prioritas.

Ringkasan#

  • Prioritas dari tinggi ke rendah adalah ** yang asosiatif ke kanan, lalu * dan /, + dan -, operator relasional, .not., .and., .or., dan terakhir .eqv. serta .neqv..
  • Pembagian dua operand integer membuang bagian pecahan, sehingga konversi dengan real() dilakukan sebelum pembagian yang hasilnya seharusnya pecahan.
  • Ekspresi campuran mengonversi operand bulat menjadi real secara otomatis, tanpa peringatan.
  • .and. dan .or. mengevaluasi short-circuit sejak Fortran 2008, sehingga syarat pengaman boleh ditulis di sebelah kiri.

Referensi#