D On in d= ini, li m, inc
Chương trình con loại thủ tục
Trong chương 8 chúng ta đã nghiên cứu về các hàm chuẩn, các hàm lệnh và các hàm do người lập trình tự xây dựng. Trong khi một hàm chỉ giới hạn ở việc tính ra một giá trị, thì các thủ tục chương trình con (hay còn gọi là thủ tục do người lập trình tự xây dựng) có thể tính ra một số giá trị, hoặc thực hiện một số thao tác. Trong bài này ta học cách viết các thủ tục và sử dụng các thủ tục trong các bài toán ứng dụng.
Nhiều quy tắc viết và sử dụng các thủ tục chương trình con giống như các quy tắc đối với các hàm chương trình con. Dưới đây liệt kê những khác biệt giữa các thủ tục và các hàm.
1) Một thủ tục không biểu diễn một giá trị, do đó tên của nó chỉ là đại diện cho một đoạn chương trình, không chỉ định kiểu của dữ liệu đầu ra. 2) Dòng lệnh đầu tiên trong một thủ tục thông báo tên thủ tục và danh sách đối số
SUBROUTINE Tên thủ tục (danh sách đối số)
3) Chương trình chính gọi một thủ tục bằng lệnh CALL có dạng tổng quát như sau:
CALL Tên thủ tục (danh sách đối số)
4) Thủ tục dùng danh sách đối số không chỉ cho đầu vào mà cả cho những giá trị gửi ra chương trình chính gọi nó. Các đối số của thủ tục được dùng trong lệnh CALL là những đối số thực tế, còn các đối số sử dụng trong thủ tục là những đối số hình thức. Các đối số trong lệnh CALL phải phù hợp về kiểu, số lượng và thứ tự với những đối số trong thủ tục.
5) Một thủ tục có thể tính ra một giá trị, nhiều giá trị hoặc không giá trị nào cả. Một thủ tục có thể sử dụng một giá trị đầu vào, nhiều giá trị đầu vào hoặc không có giá trị đầu vào.
6) Nhãn lệnh, tên biến trong thủ tục được chọn độc lập với chương trình chính. Những biến dùng trong thủ tục mà không phải là các đối số của thủ tục gọi là các biến cục bộ, các giá trị của chúng không xử lý được trong chương trình chính.
7) Cần đặc biệt thận trọng khi sử dụng các mảng nhiều chiều trong các thủ tục. Nên chỉ định cả kích thước khai báo và kích thước sử dụng thực tế với các mảng hai hoặc nhiều chiều.
8) Giống như các hàm, lệnh RETURN ở cuối các thủ tục dùng để chuyển điều khiển trở về chương trình chính, lệnh END để báo kết thúc thủ tục. 9) Trong lưu đồ khối các thao tác được thực hiện bên trong thủ tục được ký hiệu bằng biểu tượng đồ họa sau đây:
↓
↓
10) Một thủ tục có thể dùng các hàm con khác hoặc gọi các thủ tục khác, nhưng nó không thể tự gọi chính nó. (Trong Fortran 90 cho phép dùng các thủ tục đệ quy có thể tự gọi chính mình.)
Những thí dụ dưới đây giúp chúng ta học cách viết các thủ tục và sử dụng nó trong chương trình chính như thế nào.
Thí dụ 27: Chương trình tính các đặc trưng thống kê: trung bình, phương sai và độ lệch chuẩn của chuỗi x gồm n số liệu quan trắc. Các công thức sau tính như sau:
x x x n i i x n i i x m D n x D n x m − = − = =∑ ∑ = = , 1 2, σ 2 1 1 .
Ta thấy rằng mỗi đại lượng trên có thể tính được bằng một hàm riêng biệt. Nhưng ta cũng có thể tính luôn một lúc cả ba đại lượng bằng cách tổ chức tính chúng trong một thủ tục. Chương trình dưới đây cho phép đọc vào kích thước n và các giá trị của chuỗi x. Sau đó gọi thủ tục STAT để tính các đặc trưng thống kê. Cuối cùng là in ra kết quả.
Thấy rằng thủ tục STAT có tất cả 5 đối số hình thức, trong đó hai đối số đầu vào là mảng một chiều X và kích thước mảng N, ba đối số đầu ra là AVER, VARI và STDV. Khi gọi thủ tục này trong chương trình chính, ta gửi vào các đối số thực tế là X, N, TBINH, PSAI và DLC. Kết quả tính trung bình, phương sai và độ lệch chuẩn trong thủ tục chương trình con được lưu vào các biến TBINH, PSAI, DLC của chương trình chính. Hãy chú ý rằng: vì thủ tục chương trình con là môđun độc lập, nên tên các đối số của nó có thể trùng với tên của các biến trong chương trình chính, trong thí dụ này là đối số X và N. ở đây ta thấy, trong chương trình con, có thể định nghĩa kích thước của mảng bằng biến N (trong lệnh REAL X(N)). Nhớ rằng điều này chỉ cho phép trong chương trình con.
PROGRAM THKE INTEGER N, I
REAL X(99), TBINH, PSAI, DLC
PRINT *, ' NHAP DO DAI CHUOI (<100)' READ *, N
PRINT *, ' NHAP CAC GIA TRI CUA X:' 5 FORMAT (1X, ' X(', I2, '): ')
DO I = 1, N WRITE (*, 5) I READ *, X (I) ENDDO
CALL STAT (X, N, TBINH, PSAI, DLC)
WRITE(*, 8) TBINH, PSAI, DLC
8 FORMAT (1X, ' T. BINH = ', F7.2, ' PH. SAI = ', * F7.2, ' DL CHUAN = ', F7.2) * F7.2, ' DL CHUAN = ', F7.2)
END
SUBROUTINE STAT (X, N, AVER, VARI, STDV)
REAL X (N), AVER, VARI, STDV INTEGER N, I
AVER = 0.0 VARI = 0.0 DO I = 1, N
AVER = AVER + X (I) VARI = VARI + X (I) * X (I) END DO
AVER = AVER / REAL (N)
VARI = VARI / REAL (N−1) − AVER * AVER STDV = SQRT (VARI)
RETURN END
Thí dụ 28: Xử lý ngày tháng. Trong thực tế xử lý số liệu quan trắc khí tượng thủy văn, ta thường hay phải để ý đến ngày tháng của số liệu. Trong mục này sẽ xét một thí dụ về xử lý ngày tháng với thí dụ sau: Viết chương trình nhập vào một ngày tháng năm bất kỳ, in ra ngày tháng năm của ngày hôm sau. Việc xác định ngày tháng năm của ngày hôm sau so với ngày tháng năm hiện tại sẽ được thực hiện trong một chương trình con thủ tục, ta gọi tên là thủ tục HOMSAU. Vì ở đây kết quả sẽ cho ra ba giá trị nguyên tuần tự chỉ ngày, tháng và năm. Chương trình có thể như sau:
PROGRAM TGNGAY
INTEGER ID, IM, IY
PRINT *, 'HAY NHAP NGAY THANG NAM BAT KY' READ *, ID, IM, IY
CALL HOMSAU (ID, IM, IY)
PRINT 20, ID, IM, IY
20 FORMAT (1X, 'NGAY HOM SAU LA ', I2, '−', I2 , '−', I4) END END
SUBROUTINE HOMSAU (D, M, Y)
D = D + 1 IF (D .GT. SNTT (M, Y)) THEN D = 1 M = M + 1 IF (M .GT. 12) THEN M = 1 Y = Y + 1 END IF END IF RETURN END INTEGER FUNCTION SNTT (M, Y) INTEGER M, Y IF (M .EQ. 2) THEN SNTT = 28
IF ((MOD(Y,100) .NE. 0 .AND. MOD(Y,4) .EQ. 0) .OR. * (MOD (Y,100) .EQ. 0 .AND. MOD (Y/100, 4) .EQ .0))
* SNTT = 29
ELSE IF (M.EQ.4.OR.M.EQ.6.OR.M.EQ.9.OR.M.EQ.11) THEN SNTT = 30 ELSE SNTT = 31 ENDIF RETURN END
Các thao tác để chuyển thành hôm sau được thực hiện trong chương trình con thủ tục HOMSAU. Hãy chú ý rằng trong thủ tục con HOMSAU lại gọi thực hiện một hàm con khác là SNTT để tính số ngày của tháng đang xét. Hàm này đã được nhắc tới trong thí dụ 26, trang 142, ở đây ghi lại để sinh viên tiện theo dõi.
Dưới đây ta xét một thí dụ về xử lý số liệu khí tượng có liên quan tới ngày tháng.
Thí dụ 29: Tính các giá trị trung bình tháng của một yếu tố khí tượng thủy văn. Giả sử với file dữ liệu về các yếu tố khí tượng thủy văn đã mô tả trong thí dụ 20 (trang 124).
Nhớ lại rằng file HONDAU.MAT có quy cách ghi như sau: Dòng trên cùng ghi tên trạm. Dòng thứ 2 có hai số nguyên viết cách nhau lần lượt chỉ tổng số ngày quan trắc và số yếu tố được quan trắc. Dòng thứ ba có 6 số nguyên viết cách nhau lần lượt chỉ ngày, tháng, năm đầu và ngày, tháng, năm cuối quan trắc. Dòng thứ 4 là tiêu đề cột liệt kê tên tất cả các yếu tố được quan trắc, mỗi tên được ghi với độ rộng 8 vị trí. Các dòng tiếp theo lần lượt ghi giá trị của các yếu tố, mỗi dòng một ngày. Các giá trị ngày của nhiệt độ không khí được ghi ở cột thứ hai của file này. Viết chương trình tính giá trị trung bình tháng của nhiệt độ không khí trong tất cả các năm quan trắc.
ở đây ta thấy, muốn tính trung bình tháng chỉ việc cộng tất cả các giá trị ngày và chia tổng cho số ngày của tháng đang xét. Nhưng vì số ngày trong mỗi tháng có thể khác nhau, nên ta cần có những thủ tục xử lý ngày tháng. Chương trình sau đây sẽ thực hiện kiểu xử lý như vậy.
REAL X, TONG, TB (100, 12)
INTEGER D1, M1, Y1, D2, M2, Y2, YDAU, M OPEN (1, FILE = ‘HONDAU.MAT’, STATUS = ‘OLD’)