Fortran menerapkan operasi aritmetika pada array secara utuh (whole array), yakni seluruh elemen diolah dalam satu ekspresi tanpa menulis indeks satu per satu. Topik ini membahas aritmetika per elemen, assignment array, fungsi elemental, serta penugasan bersyarat dengan where. Setelah membacanya, perhitungan yang lazimnya memerlukan perulangan eksplisit dapat ditulis sebagai satu ekspresi array yang menyatakan maksudnya secara langsung.
Aritmetika per elemen dan assignment#
Operator +, -, *, /, dan ** bekerja per elemen apabila salah satu operannya berupa array. Ekspresi a + b menghasilkan array yang setiap elemennya merupakan jumlah elemen a dan b pada posisi yang sama, sedangkan 2.0 * a mengalikan setiap elemen dengan skalar. Satu-satunya syaratnya adalah kedua operan array saling cocok bentuk (conformable), yakni berbentuk sama, atau salah satu operannya berupa skalar. Assignment, yakni pemberian nilai melalui tanda sama dengan, mengikuti aturan yang sama, sehingga c = a menyalin seluruh elemen a ke c tanpa perulangan apa pun.
Program berikut mencontohkan operasi-operasi tersebut pada array empat elemen, dan hasil setiap operasi dicetak satu baris. Setiap pernyataan disertai komentar yang menyebut operasinya. Semua baris keluarannya dapat dihitung ulang dengan cepat karena nilai yang dipilih sederhana.
program demo_operasi
implicit none
real :: a(4) = [1.0, 4.0, 9.0, 16.0]
real :: b(4) = [10.0, 20.0, 30.0, 40.0]
real :: c(4)
c = a + b ! penjumlahan per elemen
print *, "a + b =", c
c = 2.0 * a ! skalar dikalikan pada tiap elemen
print *, "2.0 * a =", c
c = sqrt(a) ! fungsi elemental bekerja per elemen
print *, "sqrt(a) =", c
where (a > 5.0) ! penugasan dengan mask logika
c = sqrt(a)
elsewhere
c = 0.0
end where
print *, "where =", c
end program demo_operasi# kompilasi program contoh
gfortran demo-operasi.f90 -o demo-operasi
# jalankan program
./demo-operasi a + b = 11.0000000 24.0000000 39.0000000 56.0000000
2.0 * a = 2.00000000 8.00000000 18.0000000 32.0000000
sqrt(a) = 1.00000000 2.00000000 3.00000000 4.00000000
where = 0.00000000 0.00000000 3.00000000 4.00000000Empat baris keluaran masing-masing berasal dari satu pernyataan assignment, dan tidak ada satu perulangan pun yang ditulis di program. Perhatikan bahwa sqrt(a) menghasilkan 1.0, 2.0, 3.0, dan 4.0 karena a memuat kuadrat dari keempat bilangan itu, sehingga hasilnya mudah diperiksa sekilas.
Fungsi elemental#
Fungsi intrinsik seperti sqrt, abs, sin, dan exp tergolong elemental, yakni didefinisikan untuk satu skalar tetapi diterapkan otomatis pada setiap elemen apabila argumennya array. Bentuk hasilnya mengikuti bentuk argumen arraynya, sehingga sqrt(a) untuk a yang berisi empat elemen menghasilkan empat nilai akar kuadrat. Fungsi yang sama tetap menerima argumen skalar, sehingga satu nama fungsi melayani dua bentuk pemanggilan.
Sifat elemental juga dapat diberikan pada fungsi buatan sendiri melalui awalan elemental pada deklarasi prosedurnya. Fungsi semacam itu ditulis untuk satu elemen skalar, sedangkan penanganan bentuk arraynya dilakukan otomatis oleh compiler pada setiap pemanggilan. Dengan cara ini, aturan perhitungan cukup ditulis satu kali untuk satu elemen, dan seluruh array mengikutinya tanpa kode tambahan.
! tidak-dijalankan
y = sqrt(a) ! array: akar kuadrat dihitung per elemen
z = sqrt(16.0) ! skalar: berfungsi seperti pemanggilan biasaPerbandingan dengan perulangan eksplisit#
Operasi utuh array hanyalah penulisan singkat untuk perulangan yang mengolah elemen satu per satu. Kedua bentuk berikut menghasilkan nilai c yang persis sama:
! tidak-dijalankan
do i = 1, 4
c(i) = a(i) + b(i) ! versi perulangan
end do
c = a + b ! versi utuh array, hasilnya samaBentuk utuh array lebih pendek, tidak memerlukan variabel kendali i, dan menyatakan maksud perhitungan secara langsung. Perulangan itu tetap terjadi, tetapi ditambahkan oleh compiler, yakni program yang menerjemahkan kode sumber menjadi program mesin. Compiler bebas menentukan urutan evaluasi antarelemen karena standar tidak menetapkannya. Kebebasan ini dipakai untuk menyusun akses memori dan perhitungan seefisien mungkin pada target mesinnya, tanpa perubahan apa pun pada kode sumbernya.
Penugasan bersyarat dengan where#
Konstruksi where membatasi sebuah assignment array hanya pada elemen yang lolos syarat. Syaratnya berupa mask, yakni array logika yang bentuknya sama dengan array yang ditugasi. Pada program di atas, where (a > 5.0) memilih elemen ketiga dan keempat karena hanya keduanya yang bernilai di atas 5.0, sehingga c berisi nol untuk dua elemen pertama dan akar kuadrat untuk dua elemen terakhir. Cabang elsewhere menampung elemen yang gagal syarat, dan cabang ini boleh ditiadakan apabila elemen tersebut tidak perlu diubah.
where melengkapi operasi utuh array untuk penugasan yang tidak berlaku seragam pada semua elemen, misalnya mengganti nilai yang berada di luar rentang wajar atau menonaktifkan hasil pengukuran yang ditandai gagal. Satu mask dapat menaungi beberapa pernyataan assignment sekaligus sebelum konstruksi ditutup dengan end where. Bentuk ini menggantikan perulangan dengan percabangan di dalamnya, sehingga niat perhitungannya tetap terbaca sebagai satu kesatuan.
Kesalahan umum#
Kesalahan pertama adalah menerapkan operasi pada array yang bentuknya berbeda. Apabila bentuk kedua operan diketahui saat kompilasi, gfortran menolaknya dengan pesan bahwa operan tidak cocok bentuk. Apabila bentuk baru diketahui saat program berjalan, misalnya pada array allocatable, pelanggaran yang sama dapat lolos tanpa pesan dan hasilnya tidak dapat dipercaya, sehingga aktifkan opsi -fcheck=bounds agar pelanggaran itu dilaporkan sebagai error saat berjalan. Samakan bentuk kedua sisi, atau gunakan section untuk memotong operannya sebelum operasi dijalankan.
Kesalahan kedua adalah memanggil fungsi elemental dengan tipe argumen yang tidak didukungnya. Fungsi sqrt hanya menerima real dan complex, sehingga pemanggilan sqrt(a) atas array integer gagal saat kompilasi dengan pesan bahwa argumennya harus bertipe REAL atau COMPLEX. Konversi dengan intrinsik real memperbaikinya, seperti pada bentuk berikut:
! tidak-dijalankan
y = sqrt(real(a)) ! konversi array integer ke real sebelum akar kuadratPerhatian serupa juga berlaku pada campuran operasi integer dan real. Ekspresi a / 2 dengan a bertipe integer melakukan pembagian bilangan bulat, sedangkan maksud perhitungannya biasanya pembagian real. Tuliskan a / 2.0 atau lakukan konversi eksplisit agar aturan tipe ekspresi mengikuti maksud perhitungannya.
Ringkasan#
- Operan array pada
+,*, dan operator lain bekerja per elemen, dengan syarat bentuknya sama atau salah satu operannya skalar. - Fungsi elemental diterapkan otomatis pada setiap elemen argumen arraynya, dan hasilnya berbentuk sama dengan argumennya.
- Operasi utuh array setara dengan perulangan eksplisit, tetapi menyatakan maksud lebih langsung dan membiarkan compiler mengatur pelaksanaannya.
wheremembatasi assignment array pada elemen yang lolos mask logika, dengan cabang opsionalelsewhere.
Referensi#
- Fortran Quickstart tutorial — fortran-lang.org — Tutorial resmi komunitas Fortran yang mencontohkan array, alur kontrol, dan prosedur modern.
- GNU Fortran compiler manual — GNU Project — Referensi intrinsik elemental seperti sqrt dan sin beserta opsi kompilasi gfortran.