Giáo trình Ngôn ngữ lập trình FORTRAN 90 – Phan Văn Tân – HUS

215 28 0
Giáo trình Ngôn ngữ lập trình FORTRAN 90 – Phan Văn Tân – HUS

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

INPUT: + AA(N*N) MANG MOT CHIEU LUU A THEO COT... Sau đ ây là ch ươ ng trình tính..[r]

(1)

NXB Đại học Quốc gia Hà Nội 2007

Từ khoá: File, hàm, lệnh , chương trình con, thủ tục, ký tự, xâu, mảng, biến, tương quan, cấu trúc, phổ, thuật toán

Tài liu Thư vin đin t Đại hc Khoa hc T nhiên có th được s dng cho mc đích hc tp nghiên cu cá nhân Nghiêm cm mi hình thc chép, in n phc v

các mc đích khác nếu khơng được s chp thun ca nhà xut bn tác gi

NGƠN NG LP TRÌNH FORTRAN 90

Phan Văn Tân

(2)

PHAN VĂN TÂN

NGƠN NG LP TRÌNH FORTRAN 90

(3)

MC LC

LỜI GIỚI THIỆU 6

MỞ ĐẦU 8

CHƯƠNG NHỮNG YẾU TỐ CƠ BẢN CỦA NGÔN NGỮ FORTRAN 10

1.1 CHẠY MỘT CHƯƠNG TRÌNH FORTRAN 10

1.2 CẤU TRÚC CHUNG CỦA MỘT CHƯƠNG TRÌNH FORTRAN 14

1.3 CẤU TRÚC CÂU LỆNH 15

1.3.1 Ý nghĩa dấu cách (Blank) 15

1.3.2 Lời thích 16

1.3.3 Dòng nối tiếp 16

1.4 KIỂU DỮ KIỆU 16

1.4.1 Lớp kiểu số (Integer, Real, Complex) 17

1.4.2 Kiểu ký tự (Character) kiểu lôgic (Logical) 20

1.4.3 Phép toán kiểu liệu 22

1.5 HẰNG 24

1.5.1 Hằng nguyên 24

1.5.2 Hằng thực 24

1.5.3 Hằng ký tự 25

1.6 TÊN BIẾN VÀ TÊN HẰNG 26

1.7 QUI TẮC KIỂU ẨN 27

1.8 PHONG CÁCH LẬP TRÌNH 29

1.9 BIỂU THỨC SỐ 29

1.9.1 Phép chia với số nguyên 30

1.9.2 Biểu thức hỗn hợp 30

1.10 LỆNH GÁN GÁN HẰNG, GÁN BIỂU THỨC 30

1.11 LỆNH VÀO RA ĐƠN GIẢN 32

1.11.1 Lệnh vào liệu 32

1.11.2 Đọc liệu từ file TEXT 33

1.11.3 Lệnh kết xuất liệu 34

1.11.4 Kết xuất máy in 35

1.12 SỬ DỤNG HÀM TRONG FORTRAN 35

BÀI TẬP CHƯƠNG 38

CHƯƠNG CÁC CÂU LỆNH CƠ BẢN CỦA FORTRAN 42

2.1 LỆNH CHU TRÌNH (DO LOOPS) 42

2.2 LỆNH RẼ NHÁNH VỚI IF 45

2.2.1 Dạng 45

2.2.2 Dạng 46

2.2.3 Dạng 47

2.2.4 Dạng 48

2.2.5 Lệnh nhảy vô điều kiện GOTO 50

2.2.6 Lệnh IF số học 51

2.3 KẾT HỢP DO VÀ IF 53

2.4 RẼ NHÁNH VỚI CẤU TRÚC SELECT CASE 54

2.5 THAO TÁC VỚI HẰNG VÀ BIẾN KÝ TỰ (CHARACTER) 56

(4)

CHƯƠNG CÁC CẤU TRÚC MỞ RỘNG 60

3.1 CHU TRÌNH DO TỔNG QUÁT VÀ CHU TRÌNH DO LỒNG NHAU 60

3.2 CẤU TRÚC IF TỔNG QUÁT VÀ CẤU TRÚC IF LỒNG NHAU 61

3.3 CHU TRÌNH NGẦM 64

3.4 ĐỊNH DẠNG DỮ LIỆU BẰNG LỆNH FORMAT 64

3.5 CHU TRÌNH LẶP KHƠNG XÁC ĐỊNH 66

3.5.1 Cấu trúc kết hợp IF GOTO 66

3.5.2 Cấu trúc DO EXIT 68

3.5.3 Cấu trúc DO WHILE…END DO 69

3.5.4 Lệnh CYCLE 70

3.5.5 Một số ví dụ chu trình lặp khơng xác định 72

BÀI TẬP CHƯƠNG 74

CHƯƠNG CHƯƠNG TRÌNH CON (SUBROUTINE VÀ FUNCTION) VÀ MODUL 78

4.1 KHÁI NIỆM 78

4.2 THƯ VIỆN CÁC HÀM TRONG 78

4.3 CÁC CHƯƠNG TRÌNH CON TRONG 79

4.3.1 Hàm (Internal FUNCTION) 79

4.3.2 Thủ tục (Internal SUBROUTINE) 80

4.4 CÂU LỆNH CONTAINS 81

4.5 MỘT SỐ VÍ DỤ VỀ CHƯƠNG TRÌNH CON TRONG 82

4.6 BIẾN TOÀN CỤC VÀ BIẾN ĐỊA PHƯƠNG 85

4.7 ĐỊNH NGHĨA HÀM BẰNG CÂU LỆNH ĐƠN 87

4.8 CHƯƠNG TRÌNH CON NGỒI 87

4.8.1 Câu lệnh EXTERNAL 89

4.8.2 Khai báo khối giao diện (INTERFACE BLOCK) 89

4.9 CÁC THUỘC TÍNH CỦA ĐỐI SỐ 91

4.9.1 Thuộc tính INTENT 91

4.9.2 Thuộc tính OPTIONAL 92

4.9.3 Thuộc tính SAVE 93

4.11 PHÉP ĐỆ QUI 95

BÀI TẬP CHƯƠNG 96

CHƯƠNG MẢNG 98

5.1 KHÁI NIỆM VỀ MẢNG TRONG FORTRAN 98

5.2 KHAI BÁO MẢNG 98

5.3 LƯU TRỮ MẢNG TRONG BỘ NHỚ VÀ TRUY CẬP ĐẾN CÁC PHẦN TỬ MẢNG 101

5.3.1 Sử dụng lệnh DATA để khởi tạo mảng 103

5.3.2 Biểu thức mảng 104

5.3.3 Cấu trúc WHERE ELSEWHERE END WHERE 104

5.4 MẢNG ĐỘNG (DYNAMICAL ARRAY) 105

5.5 KIỂU CON TRỎ 107

5.5.1 Trạng thái trỏ 109

5.5.2 Cấp phát giải phóng biến trỏ 109

5.6 HÀM TRẢ VỀ NHIỀU GIÁ TRỊ 110

BÀI TẬP CHƯƠNG 111

CHƯƠNG BIẾN KÝ TỰ 115

6.1 KHAI BÁO BIẾN KÝ TỰ 115

(5)

6.3 XỬ LÝ BIẾN KÝ TỰ 116

6.4 PHÉP TOÁN GỘP XÂU KÝ TỰ 121

6.5 TẠO ĐỊNH DẠNG FORMAT BẰNG XÂU KÝ TỰ 121

6.6 MẢNG XÂU KÝ TỰ 122

BÀI TẬP CHƯƠNG 123

CHƯƠNG KIỂU FILE 125

7.1 KHÁI NIỆM 125

7.2 PHÂN LOẠI FILE 127

7.2.1 File có định dạng (Formatted Files) 127

7.2.2 File không định dạng (Unformatted Files) 127

7.2.3 File dạng nhị phân (Binary Files) 128

7.2.4 File truy cập (Sequential-Access Files) 128

7.2.5 File truy cập trực tiếp (Direct-Access Files) 128

7.3 TỔ CHỨC DỮ LIỆU TRONG FILE 129

7.3.1 File truy cập có định dạng 129

7.3.2 File truy cập trực tiếp có định dạng 130

7.3.3 File truy cập không định dạng 131

7.3.4 File truy cập trực tiếp không định dạng 132

7.3.5 File truy cập dạng nhị phân 133

7.3.6 File truy cập trực tiếp dạng nhị phân 133

7.4 LỆNH MỞ (OPEN) VÀ ĐÓNG (CLOSE) FILE 134

7.4.1 Lệnh mở file 134

7.4.2 Lệnh đóng file 137

7.5 CÁC LỆNH VÀO RA DỮ LIỆU VỚI FILE 138

7.5.1 Lệnh đọc liệu từ file (READ) 138

7.5.2 Lệnh ghi liệu file (WRITE) 139

7.5.3 Vào liệu với NAMELIST 141

7.5.4 Một số ví dụ thao tác với file 143

BÀI TẬP CHƯƠNG 146

CHƯƠNG MỘT SỐ KIẾN THỨC MỞ RỘNG 149

8.1 KHAI BÁO DÙNG CHUNG BỘ NHỚ 149

8.1.1 Lệnh COMMON 149

8.1.2 Lệnh EQUIVALENT 150

8.2 CHƯƠNG TRÌNH CON BLOCK DATA 151

8.3 CÂU LỆNH INCLUDE 151

8.4 LỆNH INQUIRE 152

8.5 ĐIỀU KHIỂN CON TRỎ FILE 154

8.5.1 Lệnh REWIND 154

8.5.2 Lệnh BACKSPACE 154

8.5.3 Lệnh ENDFILE 154

8.6 CẤU TRÚC DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 155

BÀI TẬP CHƯƠNG 159

CHƯƠNG MỘT SỐ BÀI TOÁN THƠNG DỤNG 160

9.1 CÁC BÀI TỐN THỐNG KÊ CƠ BẢN 160

9.1.1 Tính trung bình số học chuỗi số liệu 160

9.1.2 Tính độ lệch chuẩn chuỗi số liệu 161

9.1.3 Sắp xếp chuỗi theo thứ tự tăng dần xác định giá trị lớn nhất, nhỏ chuỗi 161

9.1.4 Xác định phân vị chuỗi 162

(6)

9.1.6 Tính số đặc trưng thống kê khác 166

9.1.7 Tính mơmen tương quan hệ số tương quan 167

9.2 MỘT SỐ BÀI TOÁN VỀ MA TRẬN 172

9.2.1 Tích hai ma trận 172

9.2.2 Định thức ma trận 173

9.2.3 Phần phụ đại số 176

9.2.4 Ma trận nghịch đảo 177

9.2.5 Giải hệ phương trình đại số tuyến tính 179

9.3 TƯƠNG QUAN VÀ HỒI QUI TUYẾN TÍNH 183

9.3.1 Xây dựng phương trình hồi qui tuyến tính 183

9.3.2 Tính hệ số tương quan riêng 185

9.3.3 Tính hệ số tương quan bội 187

9.4 PHƯƠNG PHÁP SỐ 188

9.4.1 Tìm nghiệm phương trình 188

9.4.2 Tính tích phân xác định 190

9.4.3 Sai phân hữu hạn đạo hàm 191

9.4.4 Toán tử Laplaxian 195

9.4.5 Giải phương trình truyền nhiệt 197

9.4.6 Xây dựng sở liệu 201

BÀI TẬP CHƯƠNG 206

TÀI LIỆU THAM KHẢO 208

PHỤ LỤC 209

1 TRÌNH TỰ CÁC CÂU LỆNH TRONG MỘT ĐƠN VỊ CHƯƠNG TRÌNH FORTRAN 209

2 TÓM TẮT CÁC CÂU LỆNH CỦA FORTRAN 209

(7)

LỜI GIỚI THIỆU

Trong năm gần đây, với phát triển mạnh mẽ Công nghệ Thông tin Điện tử Viễn thơng, nhiều chương trình, phần mềm máy tính đời ứng dụng rộng rãi, góp phần thúc đẩy phát triển kinh tế, xã hội Trong số đó, ngơn ngữ lập trình ngày phát triển phổ biến Ngơn ngữ lập trình Fortran ngoại lệ Từ phiên

đầu tiên với nhiều hạn chế Fortran ngôn ngữ thông dụng

được ưa chuộng lập trình giải toán khoa học kỹ thuật Với nhiều mạnh vượt trội so với ngơn ngữ lập trình khác, Fortran thường ứng dụng để giải tốn lớn, địi hỏi phải xử lý tính tốn nhiều, tính tốn song song

Trước năm chín mươi kỷ hai mươi, mà hệ máy PC lạở Việt Nam, toán ứng dụng chạy máy tính lớn (MINSK−32, EC−1022, EC−1035, IBM−360,…) với chương trình thường lập ngơn ngữ Fortran Song, máy PC ngày phổ biến hơn, với nhiều phần mềm tiện dụng kèm, thêm vào sựđịi hỏi

cấu hình máy tính Fortran, ngôn ngữ Fortran hầu nhưđã bị lãng quên thời gian dài Nhiều người phải thay đổi thói quen sử dụng Fortran, tự thích ứng cách chuyển sang tiếp cận với ngôn ngữ lập trình khác chuyển hướng nghiên cứu Sự thiếu thông tin cập nhật làm nhiều người tưởng Fortran ngôn ngữ “cổ” rồi, không dùng Nhưng khơng phải

vậy Trước sựđịi hỏi phải giải tốn lớn (chúng tơi muốn nhấn mạnh lớp toán khoa học kỹ thuật), chạy chếđộ thời gian thực (Real−time), Fortran ngày phát triển hoàn thiện với nhiều đặc điểm Điều hút nhiều người quay với Fortran Một lý khác có tác động không nhỏ, khiến người ta tiếp tục lựa chọn ngôn ngữ lập trình Fortran trình quan hệ hợp tác quốc tế Khi làm việc với đối tác nước ngoài, nhiều lĩnh vực hầu hết chương trình viết ngơn ngữ Fortran, khơng biết nó, đồng nghĩa với việc đơi bên khơng “tiếng nói”; dẫn đến bất lợi, hiệu làm việc với

Nhận thức tầm quan trọng vấn đề này, năm gần đây, ngơn ngữ lập trình Fortran

đã đưa vào chương trình đào tạo số khoa trường Đại học Khoa học Tự nhiên, Đại học Quốc gia Hà Nội Mặt khác, nhiều nhà khoa học, ngôn ngữ Fortran trở thành công cụ làm việc khơng thể thiếu, tất nhiên sốđó có

Bởi vậy, sách đời với kỳ vọng cung cấp cho bạn đọc kiến thức ngôn ngữ lập trình Fortran 90 Qua bạn đọc có thểứng dụng cách hiệu lĩnh vực chun mơn Quyển sách có thểđược dùng làm giáo trình giảng dạy

ở bậc đại học sau đại học cho ngành Khí tượng Thủy văn Hải dương học, trường Đại học Khoa học Tự nhiên, Đại học Quốc gia Hà Nội Tuy nhiên mong muốn giúp cho sinh viên bậc đào tạo thuộc ngành khoa học khác, Vật lý học, Hóa học, Tốn học trường

(8)

Quyển sách làm tài liệu tham khảo cho cán bộ, kỹ sư, nhà nghiên cứu thuộc nhiều lĩnh vực khác

Trong trình biên soạn sách, số đồng nghiệp đề xuất đưa thêm vào phần đồ họa Fortran Một số khác lại đề nghị gắn phần giao diện kết tính tốn kết xuất với số phần mềm đồ họa khác, GrADS, NCAR Graphics,… Chúng xin chân thành cám ơn ghi nhận ý kiến đóng góp q báu Nhận thấy phần đồ họa Fortran tích hợp số phiên chạy mơi trường Microsoft Windows; cịn để gắn kết file kết xuất Fortran với phần mềm đồ họa khác cần phải có số kiến thức

các phần mềm Vì khn khổ sách có hạn, chúng tơi cố gắng trình bày nội dung ấn phẩm khác tương lai

Mặc dù cố gắng chuyển tải nội dung sách cho đáp ứng nhiều đối tượng, từ người làm quen người có q trình làm việc định với ngơn ngữ Fortran, với bố cục từ dễđến khó, từđơn giản đến phức tạp, song nhiều hạn chế

kinh nghiệm kiến thức, sách không tránh khỏi khiếm khuyết Chúng mong nhận sựđóng góp ý kiến tất bạn đọc

Để hồn thành sách này, chúng tơi nhận hỗ trợ tinh thần vật chất từ phía trường Đại học Khoa học Tự nhiên, Đại học Quốc gia Hà Nội, đặc biệt từ đồng nghiệp thuộc Khoa Khí tượng Thủy văn Hải dương học trường, nơi chúng tơi gắn bó công tác giảng dạy hoạt động khoa học hàng chục năm Nhân xin bày tỏ lòng biết ơn chân thành lời cám ơn sâu sắc

Hà Nội, 2−2005

(9)

MỞ ĐẦU

Tập hợp qui tắc đặc biệt để mã hố kiến thức cho máy tính hiểu gọi ngơn ngữ lập trình Có nhiều ngơn ngữ vậy, ví dụ FORTRAN, BASIC, Pascal, C, FORTRAN tên cấu tạo từ FORmula TRANslation (diễn dịch cơng thức, hay cịn gọi cơng thức dịch), ngơn ngữ lập trình bậc cao Nó sử dụng tên tượng trưng để biểu diễn định lượng toán học viết cơng thức tốn học dạng thức hợp lý hiểu được,

X = (−B+DELTA)/(2*A) Ý tưởng FORTRAN John Backus đề xuất vào khoảng cuối năm 1953 New York, chương trình FORTRAN chạy vào tháng năm 1957

Kể từđó, việc sử dụng FORTRAN nhanh chóng phổ biến rộng rãi Điều địi hỏi cần phải sớm tiêu chuẩn hố cho chương trình viết phải bảo đảm chạy nơi Vào năm 1966, lần phiên chuẩn ngơn ngữ lập trình ấn hành Phiên này, nhưđã biết, Fortran 66 (chính xác FORTRAN 66, thực tế người ta cho cách viết hoa không trang trọng) Phiên chuẩn sau đó, Fortran 77, ấn hành vào năm 1978 Khơng lịng với cạnh tranh ngôn ngữ khác, Pascal C, FORTRAN tiếp tục phát triển cách mạnh mẽ Và phiên chuẩn gần đây, FORTRAN 90 (hoặc Fortran 90), với nhiều đặc tính đột phá, đời vào tháng năm 1991 Cho đến nay, FORTRAN phát triển đến phiên hơn, FORTRAN 95, FORTRAN 2003 Trong khuôn khổ sách hạn chế

trình bày kiến thức FORTRAN 90 Những phần bổ sung phiên sau so với FORTRAN 90 không nhiều chưa cần thiết phải đưa vào Trong số tình cụ thể, để giúp người đọc làm quen với FORTRAN 77 cần có thêm kiến thức đểđọc chương trình người khác viết FORTRAN 77, chúng tơi có thêm ghi “mở rộng” thích hợp Những người thành thạo Fortran muốn quan tâm đến lịch sử phát triển ngôn ngữ lập trình tham khảo thêm Fortran 90 Explained, Oxford University Press (Oxford, 1990) Michael Metcalf John ReidMetcalf Reid

Nhưđã nói trên, xác nên viết ngơn ngữ FORTRAN, “sở thích tuỳ tiện”, chúng tơi viết Fortran thay cho cách viết FORTRAN

Quyển sách bố cục chương Chương 1: Những yếu tố ngôn ngữ

(10)

cập đến khái niệm thư viện hàm chuẩn Fortran, chương trình trong, chương trình ngồi modul, số kiến thức khác Chương trình bày kiến thức mảng Fortran, cách khai báo mảng, lưu trữ mảng nhớ truy cập đến phần tử mảng Chương trình bày biến ký tự xử lý biến ký tự Chương cung cấp kiến thức file,

phân loại file, tổ chức liệu file, lệnh vào liệu với file Chương 8: Một số kiến thức mở rộng Ởđây trình bày cách khai báo dùng chung nhớ ứng dụng, chương trình BLOCK DATA, cấu trúc liệu người dùng định nghĩa số câu lệnh thường gặp khác Chương dẫn số tốn thơng dụng, lớp toán thống kê, toán ma trận, tương quan hồi qui tuyến tính, phương pháp số Cuối chương hệ thống tập tự giải, nhằm củng cố

những kiến thức có liên quan

(11)

CHƯƠNG NHỮNG YẾU TỐ CƠ BẢN CỦA NGÔN NGỮ FORTRAN

1.1 CHẠY MỘT CHƯƠNG TRÌNH FORTRAN

Cũng bắt đầu học ngơn ngữ lập trình khác, người làm quen với Fortran, ta nên chạy chương trình ví dụ phần sớm tốt, không cần cố gắng hiểu cách chi tiết chúng làm việc Việc giải thích chúng giới thiệu phần sau Để chạy chương trình trước hết ta cần phải có phần mềm biên dịch

đã cài đặt hệ thống máy tính Ngồi ra, ta cần phải làm quen với phần mềm này, phải biết cách soạn thảo chương trình Fortran biên dịch chạy Việc làm quen không nhiều thời gian đơn giản, nên khơng trình bày ởđây Hơn nữa, Fortran làm việc nhiều hệđiều hành khác nhau, dòng UNIX, LINUX, WINDOWS, DOS,… có nhiều phiên khác hệđiều hành, nên không đầy đủ trình bày ởđây một vài trường hợp

Chương trình sau sẽđưa lời chào mừng, ta đưa tên vào hỏi: Ví dụ 1.1 Chương trình làm quen

! Vi du mo dau ! Loi Chao mung!

CHARACTER NAME*20 PRINT*, 'Ten ban la gi?' READ*, NAME

PRINT*, 'Xin chao ban ', NAME END

Kết nhận hình chạy chương trình sau (câu trả lời dòng chữ in nghiêng):

Ten ban la gi? Nam

Xin chao ban Nam

Tuy nhiên, với chương trình trên, ta gõ tên đầy đủ Họ tên, từ có dấu cách kết bất ngờđấy Nhưng khơng sao, tìm hiểu vấn đề sau

(12)

khó chịu so sánh Fortran với số ngôn ngữ khác Nhưng ta cảm thấy tự hài lòng với khiếm khuyết nhỏ so với khả tuyệt vời Fortran

Chương trình sau cho phép tính giá trị hàm A(t) = 174.6(t−1981.2)3 nhập vào giá trị biến t

Ví dụ 1.2: Tính giá trị hàm !

PROGRAM TinhHam

! Tinh gia tri ham A(t)=174.6*(t1981.2)**3 INTEGER T ! Biến nguyên lưu giá trị biến t REAL A ! Biến thực lưu giá trị hàm A(t) PRINT*,’Cho gia tri cua bien t:’

READ*, T

A = 174.6 * (T - 1981.2) **

PRINT*,'Gia tri ham A(t) t= ', T, ' la : ', A END PROGRAM TinhHam

Khi chạy chương trình này, hình xuất dịng chữ (phía dịng trỏ

màn hình ( ) nhấp nháy): Cho gia tri cua bien t:

Nếu đưa vào giá trị 2000 (cho biến t) ta nhận kết quả: Gia tri ham A(t) t = 2000 la : 1.1601688E+06

Giá trị kết hàm in dạng ký hiệu khoa học E+06, có nghĩa số trước nhân với 10 luỹ thừa 6, tức trị số A(t) vào khoảng 1,16 triệu Bây ta chạy chương trình nhiều lần, lần thay đổi giá trị biến t thử tìm xem giá trị hàm A(t) sẽđạt khoảng 10 triệu Sau đó, thử gõ nhầm giá trị t (ví dụ gõ vào 2,000 thay gõ 2000) để xem Fortran phản ứng lại

Một ví dụ khác, giả sử ta có 1000 đôla gửi tiết kiệm ngân hàng với lãi suất 9% năm Vậy, sau năm số tiền có ngân hàng bao nhiêu?

Để lập chương trình cho máy tính giải tốn trước hết cần phải làm rõ vấn đề mặt nguyên tắc Nhận thấy rằng, số tiền có sau năm tổng số tiền gốc gửi số tiền lãi có Như vậy, lơgic bước thực toán là:

1) Nhập số liệu vào máy (số tiền gốc lãi suất) 2) Tính tiền lãi (tức 9% 1000, 90)

3) Cộng tiền lãi vào số tiền gốc (90 + 1000, tức 1090) 4) In (hiển thị) số tiền có sau năm

(13)

Ví dụ 1.3: Tính tiền gửi tiết kiệm

! Chuong trinh khong nhap du lieu tu ban phim PROGRAM TinhTien

! Tinh tien gui tiet kiem

REAL SoTien, TienLai, LaiSuat

SoTien = 1000.0 ! Số tiền gốc ban đầu LaiSuat = 0.09 ! Lãi suất

TienLai = LaiSuat * SoTien SoTien = SoTien + TienLai

PRINT*, 'So tien se co sau mot nam:', SoTien END PROGRAM TinhTien

Ta gõ chương trình vào máy chạy tính, ý máy khơng địi hỏi phải nhập đầu vào (input) từ bàn phím ví dụ trước (Tại sao?) Kết nhận hình

là:

So tien se co sau mot nam: 1.0900000E+03

Sẽ có ích ta cố gắng thực lặp lại nhiều lần ví dụ đây, lần thử

sửa đổi chương trình theo dõi xem kết thay đổi Điều sẽ giúp cho ta tự tin tiếp cận với nội dung sau Fortran

Bây ta tìm hiểu xem trình thực hiện, chương trình Fortran làm Nói chung, sau gõ lời chương trình (source code) tiến hành chạy (run) mơi trường hệđiều hành máy tính thích hợp (đã cài đặt phần mềm Fortran), có hai q trình tách biệt xảy

Đầu tiên, chương trình biên dịch (compile), tức câu lệnh dịch (translated) sang mã máy (machine code) cho máy tính hiểu Q trình xảy sau Trước hết câu lệnh chương trình sẽđược kiểm tra cú pháp (Syntax) Nếu khơng có lỗi, chúng sẽđược dịch sang mã máy lưu trữ vào file gọi đối tượng (Object) hay đích Sau chúng sẽđược liên kết (Link) với hệ thống thư viện chuẩn Fortran để tạo thành file thực (executable) Nếu chương trình cịn lỗi, lỗi sẽđược q trình biên dịch kết thúc mà khơng tạo file đích, đó khơng xảy q trình thứ hai Nếu trình thứ thực thành cơng chuyển sang q trình thứ hai, chương trình dịch (tức file thực được) sẽđược thực (executed) Ở bước thịđã dịch chương trình thực theo qui tắc lập

Bộ chương trình thực trọn vẹn trình thứ (tức tạo file thực − executable) thường gọi trình biên dịch (compiler)

Trong biên dịch, không gian nhớ RAM máy tính định vị cho liệu sẽđược phát sinh chương trình Phần nhớ hiểu “vùng” nhớ khu trú mà chúng, thời điểm, xác định giá trị liệu Các nhớ khu trú

(14)

là cấp phát số 1000.0 đến vị trí nhớ có tên SoTien Vì nội dung SoTien thay đổi chương trình chạy nên gọi biến (variable)

Về hình thức, chương trình tính tiền gửi tiết kiệm (ví dụ 1.3) biên dịch sau: 1) Đưa số 1000 vào vị trí nhớSoTien

2) Đưa số 0.09 vào vị trí nhớLaiSuat

3) Nhân nội dung LaiSuat với nội dung SoTien đưa kết vào vị trí nhớ TienLai

4) Cộng nội dung SoTien với nội dung TienLai đưa kết vào SoTien 5) In (hiển thị) thông báo nội dung SoTien

6) Kết thúc

Khi chạy chương trình, câu lệnh dịch thực theo thứ tự từ xuống Quá trình thực hiện, vị trí nhớđược sử dụng có giá trị sau:

SoTien : 1000 LaiSuat: 0.09 TienLai: 90 SoTien : 1090

Chú ý nội dung ban đầu SoTienđã bị thay giá trị

Câu lệnh PROGRAM ở dòng thứ hai ví dụ 1.3 mởđầu cho chương trình Nó câu lệnh tuỳ chọn, có thể kèm theo tên tuỳ ý Dòng thứ dòng thứ ba, bắt đầu với dấu chấm than, lời giải thích, có lợi cho người đọc chương trình, khơng ảnh hưởng tới chương trình dịch Các biến chương trình có kiểu (type) khác nhau; câu lệnh REAL ví dụ khai báo kiểu Các dịng trống (nếu có) chương trình xem câu lệnh không thực (non-executable), tức khơng có tác động thực hiện, chèn thêm vào chương trình sáng sủa, không rối mắt

Bây ta thử làm lại ví dụ sau 1) Chạy chương trình ghi nhớ lại kết

2) Thay đổi câu lệnh thực SoTien = 1000.0 câu lệnh SoTien = 2000.0 chạy lại chương trình Rõ ràng hiểu kết lại khác với kết trước

3) Tiếp đến, loại bỏ dòng lệnh SoTien = SoTien + TienLai

và chạy lại chương trình Kết nhận số tiền không thay đổi! Như vậy, loại bỏ dòng lệnh SoTien = SoTien + TienLai

(15)

Tóm lại, để giải tốn lập trình với ngơn ngữ Fortran ta cần thực theo trình tự

các bước sau:

1) Phân tích tốn, xác định thuật giải, bước thực trình tự thực bước

Đây bước quan trọng, định sựđúng đắn mặt lôgic việc giải tốn Do

đó, nói chung ta nên lập dàn cụ thể biểu diễn qua sơđồ (thường gọi sơđồ khối) 2) Soạn thảo mã nguồn chương trình (chương trình nguồn, hay lời chương trình), tức ngơn ngữ hố thuật giải, theo trình tựđã lập lưu vào (hoặc số) file với phần mở

rộng *.f90 (hoặc *.f, *.for, ngầm định Fortran 77)

3) Tiến hành biên dịch chương trình Ở bước chương trình cịn lỗi cú pháp ta

quay lại bước 2) để chỉnh sửa tiếp tục biên dịch lại chương trình Quá trình tiếp diễn trình biên dịch tạo file đích (Ojective file) thực liên kết (link) để nhận file thực (executable file)

4) Chạy chương trình (tức chạy file thực hiện) để nhận kết Sau nhận kết

tính ta cần phân tích, xem xét tính hợp lý, đắn Nếu kết khơng phù hợp cần phải xem xét lại bước 1) bước 2)

1.2 CẤU TRÚC CHUNG CỦA MỘT CHƯƠNG TRÌNH FORTRAN

Cấu trúc chung chương trình Fortran đơn giản sau (những phần đặt dấu ngoặc vuông tuỳ chọn, có, khơng):

[PROGRAM TenChuongTrinh] [Cac_cau_lenh_khai_bao] [Cac_cau_lenh_thuc_hien]

END [PROGRAM [TenChuongTrinh]]

Như thấy, có câu lệnh bắt buộc chương trình Fortran END Câu lệnh báo cho chương trình dịch khơng cịn câu lệnh để dịch

Ký hiệu

END [PROGRAM [TenChuongTrinh]]

có nghĩa bỏ qua TenChuongTrinh câu lệnh END, có TenChuongTrinh từ khoá PROGRAM bắt buộc

TenChuongTrinh tên của chương trình, thường đặt cách tùy ý cho mang tính gợi nhớ, chương trình giải vấn đề Cac_cau_lenh_khai_bao câu lệnh khai báo biến, hằng, kiểu liệu tương ứng chúng để trình biên dịch cấp phát nhớ, phân luồng xử lý Cac_cau_lenh_thuc_hien câu lệnh xác định qui tắc trình tự thực tính tốn, xử

(16)

Trong cấu trúc trên, mục (nếu có) bắt buộc phải xuất theo trình tự nhưđã mơ tả Có nghĩa sau câu lệnh mơ tả tên chương trình câu lệnh khai báo, câu lệnh thực Câu lệnh END phải đặt cuối chương trình

1.3 CẤU TRÚC CÂU LỆNH

Dạng câu lệnh chương trình Fortran 90 gồm từ đến 132 ký tự (câu lệnh trống rỗng; câu lệnh trống rỗng làm cho chương trình dễđọc phân cách lơgic đoạn) Đối với phiên Fortran 77 phiên trước đó, nội dung câu lệnh phải cột thứ kéo dài tối đa đến cột thứ 72 Nếu câu lệnh có nội dung dài hơn, sẽđược ngắt xuống dịng dưới, dịng nối tiếp phải có ký tự (khác dấu cách) xuất cột thứ Bạn

đọc cần lưu ý đặc điểm sử dụng chương trình người khác, mình, lập trình với phiên Fortran 77 trước Fortran 90 khơng có hạn chếđó

Một câu lệnh có nhãn Nhãn số nguyên dương khoảng 1−99999 Nhãn (nếu có) phải chương trình phải đặt ởđầu câu lệnh, phân cách với nội dung câu lệnh dấu cách Đối với Fortran 77 phiên trước, nhãn ghi vào cột 1−5

Tất câu lệnh, trừ câu lệnh gán (ví dSotien = 1000.0), bắt đầu từ khoá (keyword) Trên gặp số từ khoá nhưEND, PRINT, PROGRAM, REAL

Nói chung dịng có câu lệnh Tuy nhiên, nhiều câu lệnh xuất dịng, chúng phải phân cách dấu chấm phẩy (;) Để cho rõ ràng, nên viết câu lệnh gán ngắn, như:

A = 1; B = 1; C = 1

Những câu lệnh dài có thểđược viết nhiều dịng phải có ký hiệu nối dịng (sẽđược trình bày đây)

1.3.1 Ý nghĩa dấu cách (Blank)

Nói chung dấu cách khơng quan trọng, ta sử dụng chúng để làm cho chương trình dễđọc cách viết thụt câu lệnh vào (thêm dấu cách vào phía bên trái) chèn vào câu lệnh Tuy nhiên, có chỗ khơng phép chèn dấu cách vào, qui ước cách viết từ khóa, tên biến, mà ta gọi ký hiệu qui ước

(17)

Tuy nhiên, tên, nhãn cần phải phân cách với từ khoá, tên, nhãn khác dấu cách Như REALX 30CONTINUE khơng phép (vì X biến, cịn 30 nhãn)

1.3.2 Lời thích

Mọi ký tự theo sau dấu chấm than (!) (ngoại trừ xâu ký tự) lời thích, chương trình dịch bỏ qua Tồn nội dung dịng lời thích Dịng trắng dịch dịng thích Lời thích dùng cách tuỳ ý để làm cho chương trình dễđọc

Đối với Fortran 77, cột có ký tự “C” “c” nội dung chứa dịng hiểu lời thích Qui tắc khơng Fortran 90 chấp nhận Nhưng thay cho ký tự

“C” “c", sử dụng ký tự dấu chấm than chúng lại tương đương 1.3.3 Dịng nối tiếp

Nếu câu lệnh dài có thểđược chuyển phần xuống dịng cách thêm ký hiệu nối dòng (&) vào cuối dòng trước ngắt phần lại xuống dòng Ví dụ:

A = 174.6 * & (T - 1981.2) **

Nhưđã nói trên, Fortran 77 sử dụng cột thứ làm cột nối dịng, cách chuyển tiếp dịng Fortran 90 khơng tương thích với Fortran 77

Dấu & cuối dịng thích khơng hiểu nối tiếp dịng thích,

đó &được xem phần thích 1.4 KIỂU DỮ KIỆU

Nhưđã thấy đây, chương trình Fortran thường bắt đầu câu lệnh khai báo biến, kiểu liệu chúng Khái niệm kiểu liệu (data type) khái niệm Fortran 90 Kiểu liệu bao gồm tập hợp giá trị liệu (chẳng hạn, toàn số), cách thức biểu thị chúng (ví dụ, −2, 0, 999), tập hợp phép tốn (ví dụ, phép tốn số học) cho phép xuất chúng

Fortran 90 định nghĩa kiểu liệu chuẩn, chia thành hai lớp lớp kiểu số (numeric) gồm số nguyên (integer), số thực (real) số phức (complex), lớp kiểu số (non-numeric) gồm kiểu ký tự (character) kiểu lôgic (logical)

Liên kết với kiểu liệu loại (kind) liệu Về điều liên quan đến khả

(18)

Ngoài kiểu liệu chuẩn đây, ta định nghĩa cho riêng kiểu liệu khác, chúng có thể có tập giá trị phép toán riêng

Gắn liền với kiểu liệu cịn có thuộc tính liệu Fortran định nghĩa nhiều thuộc tính, sau đây số thuộc tính thơng dụng:

PARAMETER: thuộc tính hằng,

DIMENSION: thuộc tính mảng,

ALLOCATABLE: thuộc tính cấp phát động,

POINTER: thuộc tính trỏ,

Thuộc tính có thểđược dùng kèm với câu lệnh khai báo kiểu liệu để mô tả kiểu liệu biến, Trong nhiều trường hợp thuộc tính có thểđược dùng độc lập câu lệnh khai báo

1.4.1 Lớp kiểu số (Integer, Real, Complex) a Kiểu số nguyên

Dữ liệu có kiểu số nguyên liệu nhận giá trị thuộc tập số nguyên, ví dụ 0, 1, 2, 3, , −5, −10, Đó tập hợp số “đếm được” hay tập có thứ tự, tức số nguyên

ln có số liền trước số liền sau Để khai báo biến có kiểu số nguyên ta sử dụng câu lệnh:

INTEGER [([KIND=]kind)][,attrs] ::] vname

Trong đó:

kind loại, nhận giá trị 1, 2, (đối với UNIX LINUX)

attrs thuộc tính, nhận một, nhiều hơn, giá trịPARAMETER, DIMENSION, ALLOCATABLE, POINTER,…

vname danh sách biến hằng, viết cách dấu phẩy

Tùy theo loại mà biến/hằng nguyên chiếm dung lượng nhớ phạm vi giá trị lớn hay nhỏ Trong bảng 1.1 dẫn miền giá trị hợp lệđối với loại số nguyên khai báo, cột biểu thị cách khai báo, cột dung lượng nhớ bị chiếm giữứng với loại số

nguyên, cột phạm vi giá trị loại số nguyên tương ứng khai báo Bảng 1.1 Miền giá trị dung lượng nhớ kiểu số nguyên Cách khai báo Số byte chiếm giữ Phạm vi giá trị

INTEGER 2 147 483 648 đến

2 147 483 647 INTEGER*1 INTEGER

(1) INTEGER (KIND=1) 1 128 đến 127 INTEGER*2 INTEGER

(2) INTEGER (KIND=2)

(19)

(4) INTEGER (KIND=4) 2 147 483 647

Các ví dụ sau cho thấy sử dụng cách khác để khai báo kiểu số nguyên cho biến,

INTEGER, DIMENSION(:), POINTER :: days, hours INTEGER(2), POINTER :: k, limit

INTEGER(1), DIMENSION(10) :: min

Tất biến khai báo có kiểu số ngun Dịng thứ khai báo biến days, hours biến mảng chiều có thuộc tính trỏ, với kích thước chưa xác định, phần tử mảng số nguyên byte; dòng thứ hai khai báo hai biến đơn (biến vơ hướng) k, limit có thuộc tính trỏ kiểu số nguyên loại byte; dòng thứ ba khai báo biến mảng min gồm 10 phần tử, phần tử số nguyên loại byte Những khai báo tương đương với cách khai báo đây:

INTEGER days, hours INTEGER(2) k, limit INTEGER(1) min

DIMENSION days(:), hours(:), (10) POINTER days, hours, k, limit

Các biến có thểđược khởi tạo giá trị ban đầu thông qua lệnh khai báo, chẳng hạn: INTEGER (2) :: k=4

INTEGER (2), PARAMETER :: limit=12

Trong khai báo trên, biến limit có thuộc tính PARAMETER nên giá trị khơng bị biến đổi trình thực chương trình Bởi gọi hằng, khác với k biến Cũng khai báo biến dạng sau đây:

INTEGER days, hours INTEGER (2):: k=4, limit DIMENSION days(:), hours(:) POINTER days, hours

PARAMETER (limit=12)

Với cách khai báo này, từ khóa DIMENSION, POINTER, PARAMETER (ở ba dòng cuối) gọi lệnh khai báo, dùng đểđịnh nghĩa biến, thuộc tính chúng

b Kiểu số thực

Kiểu số thực nói chung gần giống với tập số thực toán học Khác với kiểu số nguyên, kiểu số thực tập hợp “không đếm được”, hay tập khơng có thứ tự Để biểu diễn số thực Fortran 90 sử

dụng hai phương pháp gần độ xác đơn độ xác kép Có thể khai báo kiểu số

thực câu lệnh:

REAL [([KIND=]kind)][[,attrs] ::] vname

Đối với số thực độ xác kép (hay độ xác gấp đơi) ta cịn sử dụng câu lệnh khai báo:

DOUBLE PRECISION [[,attrs] ::] vname

(20)

kind loại, nhận giá trị 4, 16 (đối với UNIX LINUX)

attrs thuộc tính, nhận một, nhiều hơn, giá trịPARAMETER, DIMENSION, ALLOCATABLE, POINTER,

vname danh sách biến hằng, viết cách dấu phẩy

Cách khai báo, phạm vi giá trị, độ xác dung lượng nhớ bị chiếm giữứng với loại số thực cho bảng 1.2, cột 1, 2, mơ tả tương tự cột 1, 2, bảng 1.1 Riêng cột thứ ởđây, số thực chỉđược biểu diễn gần nên giá trị chúng chỉđạt độ xác định tùy theo dung lượng nhớ dùng để mơ tả chúng Độ xác trường hợp hiểu số chữ số biểu diễn xác giá trị biến/hằng thực Ví dụ, chạy chương trình sau

REAL X

X = 123456789.0 PRINT '(F30.2)', X end

ta nhận kết hình là: X= 123456800.00

Có lẽ bạn đọc ngạc nhiên, biến x chỉđược gán giá trị in mà giá trị in lại khác với giá trị gán vào? Nguyên nhân khác chỗ, ta khai báo biến x loại số thực byte, có chữ sốđầu tiên biểu diễn xác giá trị biến x

Bảng 1.2 Miền giá trị dung lượng nhớ kiểu số thực Cách khai báo

Số

byte chiếm

giữ

Độ

chính xác

(số

chữ

số)

Phạm vi giá trị

REAL REAL*4 REAL (KIND=4)

4 6 3.4028235E+38 đế0; n 1.1754944E38; +1.1754944E38 đến +3.4028235E+38 REAL*8

REAL (KIND=8) DOUBLE PRECISION

8 15 1.797693134862316D+308 2.225073858507201D308; đến 0;

+2.225073858507201D308 đến +1.797693134862316D+308 Sau số ví dụ khai báo biến, có kiểu số thực

! Khai bao cac bien co kieu du lieu so thuc REAL X, Y(10)

REAL*4 A,B

REAL (KIND=8), DIMENSION (5) :: U,V

DOUBLE PRECISION, DIMENSION (:), ALLOCATABLE :: T REAL, PARAMETER :: R_TDat = 6370.0

(21)

thứ tư khai báo biến mảng thuộc tính động T có độ xác gấp đơi, tức phần tử mảng chiếm byte; dòng cuối khai báo đơn R_TDat, có giá trị khởi tạo 6370.0

c Kiểu số phức

Số phức định nghĩa cặp có thứ tự hai số thực gọi phần thực phần

ảo Dữ liệu kiểu số phức khai báo câu lệnh: COMPLEX [([KIND =]kind)] [[,attrs] :: ] vname

Trong tham số kind nhận giá trị 8; tham số attrs nhiều thuộc tính, nhận giá trị PARAMETER, DIMENSION, ALLOCATABLE, POINTER,…; vname danh sách biến hằng, viết cách dấu phẩy

Độ xác phạm vi giá trị kiểu số phức độ xác phạm vi giá trị phần thực phần ảo Dung lượng nhớ chiếm giữ số phức dung lượng hai số thực Bảng 1.3 liệt kê cách khai báo số byte chiếm giữ biến, có kiểu số phức

Ví dụ, câu lệnh:

COMPLEX (4), DIMENSION (8) :: cz, cq

khai báo hai biến phức cz cq, biến mảng gồm phần tử phức, tức cặp số thực, số thực chiếm byte Câu lệnh tương đương với hai câu lệnh sau:

COMPLEX(4) cz, cq DIMENSION(8) cz, cq

Bảng 1.3 Miền giá trị dung lượng nhớ kiểu số phức

Cách khai báo Số byte chiếm giữ

COMPLEX COMPLEX *4 COMPLEX (4) COMPLEX (KIND=4)

8

COMPLEX *8 COMPLEX (8) COMPLEX (KIND=8) DOUBLE CPMPLEX

16

1.4.2 Kiểu ký tự (Character) kiểu lôgic (Logical) a Kiểu ký tự

Kiểu ký tự có tập giá trị ký tự lập thành xâu (chuỗi) ký tự Độ dài xâu số ký tự

trong xâu khai báo Mỗi ký tự xâu ký tự chiếm byte nhớ Do đó, số byte chiếm giữ

bộ nhớ biến, kiểu ký tự tùy thuộc độ dài xâu Câu lệnh tổng quát khai báo biến, kiểu ký tự cách sau

Cách 1:

CHARACTER (length) vname

Trong length số nguyên dương chỉđộ dài cực đại vname; vname danh sách tên biến, có kiểu xâu ký tự, viết cách dấu phẩy

(22)

CHARACTER (type[,type…])[attrib[,attrib]…] :: vname

Với type tham sốđộ dài loại, nhận dạng: (LEN = type-value)

(KIND = expr)

(KIND = expr, LEN = type-value) ([LEN =] type-value, KIND = expr)

trong type−value có thể dấu (*), nguyên không dấu, biểu thức nguyên; expr biểu thức xác định giá trị nguyên tương ứng với phương pháp biểu diễn ký tự (chẳng hạn, chữ

cái Latinh, chữ Hylạp,…)

attrib một nhiều thuộc tính, viết cách dấu phẩy Nếu thuộc tính sau

đó phải sử dụng dấu (::) Các thuộc tính là: ALLOCATABLE, DIMENSION, PARAMETER, POINTER,

Cách 3:

CHARACTER [*chrs] vname [*lengths][(dim)] & [/values/][,vname [*lengths][(dim)]] [/values/]

Trong đó: chrs độ dài (cực đại) xâu, số ngun khơng dấu, biểu thức nguyên nằm ngoặc đơn, dấu nằm ngoặc đơn (*); lengths độ dài (cực đại) xâu, số ngun khơng dấu, biểu thức nguyên nằm ngoặc đơn, dấu nằm ngoặc đơn (*); dim: khai báo mảng, tức vname mảng; /values/ liệt kê ký tự, tức giá trị biến, vname

Ví dụ:

CHARACTER (20) St1, St2*30 CHARACTER wt*10, city*80, ch

CHARACTER (LEN = 10), PRIVATE :: vs CHARACTER*(*) arg

CHARACTER name(10)*20

CHARACTER(len=20), dimension(10):: plume CHARACTER(2) susan,patty,alice*12,dotty, jane(79) CHARACTER*5 word /'start'/

Các khai báo có ý nghĩa sau: biến St1 có độ dài cực đại 20 ký tự, biến St2

độ dài cực đại 30 ký tự; biến wt, city, ch tương ứng có độ dài cực đại 10, 80 ký tự; biến vs có độ dài cực đại 10 ký tự có thuộc tính PRIVATE; biến arg có độ dài khơng xác

định; biến mảng chiều name, plume mảng gồm 10 phần tử, phần tử xâu có độ

dài cực đại 20 ký tự; biến susan, patty, dotty có độ dài cực đại ký tự, biến alice có độ dài cực

đại 12 ký tự biến mảng jane gồm 79 phần tử, phần tử xâu dài ký tự; biến word dài tối

đa ký tự khởi tạo giá trịđầu 'start' b Kiểu lôgic

(23)

LOGICAL [([KIND=]kind)] [, attrs ::] vname

Trong đó:

kind: độ dài tính byte, nhận giá trị 1, 2,

attrs: thuộc tính, nhận nhiều giá trị, phân cách dấu phẩy vname: Danh sách biến, hằng, phân cách dấu phẩy

Số byte chiếm giữ nhớ kiểu liệu logic phụ thuộc vào loại liệu mô tả bảng 1.4

Bảng 1.4 Miền giá trị dung lượng nhớ kiểu lôgic

Cách khai báo Loại (KIND) Số byte chiếm giữ

LOGICAL 4

LOGICAL*1 LOGICAL (1)

LOGICAL (KIND=1) 1 1

LOGICAL*2 LOGICAL (2) LOGICAL (KIND=2)

2 4

LOGICAL*4 LOGICAL (4) LOGICAL (KIND=4)

4 4

Ví dụ, câu lệnh sau khai báo biến có kiểu lôgic dạng khác nhau: LOGICAL, ALLOCATABLE :: flag1, flag2

LOGICAL (2), SAVE :: doit, dont = FALSE. LOGICAL switch

Cách khai báo hồn tồn tương đương với câu lệnh khai báo sau đây: LOGICAL flag1, flag2

LOGICAL (2) doit, dont = FALSE. ALLOCATABLE flag1, flag2 SAVE doit, dont

1.4.3 Phép toán kiểu liệu

Trong ví dụ trước ta thấy số biểu thức viết ngơn ngữ Fortran có sử

dụng số phép toán, phép nhân hai số, phép cộng hai số, Tuy nhiên, với kiểu liệu khác nhau, phép tốn chúng khác Sau trình bày chi tiết vấn

đề

Nói chung, Fortran định nghĩa bốn lớp phép toán tương ứng với kiểu liệu mô tả:

− Phép toán số học: Sử dụng với kiểu số nguyên, số thực số phức

− Phép toán quan hệ, hay phép toán so sánh: Sử dụng với kiểu số nguyên, số thực, kiểu ký tự, có thểđối với số phức trường hợp so sánh khơng

− Phép tốn lơgic: Sử dụng với kiểu lơgic, với số nguyên

(24)

Bảng 1.5 liệt kê ký hiệu phép toán, thứ tự ưu tiên, thứ tự thực biểu thức ý nghĩa chúng, thứ tựưu tiên xếp cho mức ưu tiên cao

Mặc dù vậy, lúc viết chương trình ta cần ý số điểm sau thực phép toán kiểu liệu khác nhau:

− Trong biểu thức số học, tốn hạng có kiểu liệu kiểu liệu kết kiểu liệu toán hạng Nếu tốn hạng khác kiểu liệu kết nhận có kiểu liệu tốn hạng có kiểu “mạnh nhất” Chẳng hạn, biểu thức gồm hỗn hợp số nguyên số

thực kết có kiểu số thực, kiểu số thực “mạnh hơn” kiểu số nguyên Tuy nhiên, gán kết quảđó cho biến kiểu kết sẽđược chuyển thành kiểu liệu biến Ví dụ, a, b, x biến thực, cịn n biến ngun thì:

a=22.9; b=6.1 => x=a+b=16.8; nhưng n=a+b=16 a=2.9; b=6.8 => x=a+b=9.7; nhưng n=a+b =

Nhưđã thấy, giá trị a+b sau gán cho n phần thập phân bị “chặt cụt”

− Kết biểu thức quan hệ biểu thức lôgic luôn nhận giá trị .TRUE. .FALSE.

Bảng 1.5 Định nghĩa phép toán Fortran

Sau mơt số ví dụước lượng giá trị biểu thức: 2 ** ** 0.5 cho kết 8

Ký hiệu phép toán

Tên gọi/Ý nghĩa Thứ

tựưu tiên

Thứ tự thực Ví dụ

Phép tốn số học

** Phép lũy thừa Phải sang trái A ** B

* Phép nhân 2 Trái sang phải A * B

/ Phép chia 2 Trái sang phải A / B

+ Phép cộng 3 Trái sang phải A + B

Phép trừ 3 Trái sang phải A B

Phép toán quan hệ

.EQ ( == )

Bằng Không phân định A.EQ.B; A == B

.LT ( < ) Nhỏ Không phân định A.LT.B; A < B .LE ( <=

)

Nhỏ Không phân định A.LE.B; A <= B .GT ( > ) Lớn Không phân định A.GT.B; A > B .GE ( >=

)

Lớn Không phân định A.GE.B; A >= B .NE ( /=

)

Không (Khác) Không phân định A.NE.B; A /= B Phép tốn lơgic

.NOT Phủđịnh Không phân định NOT L1

.AND Và (Phép hội) 2 Trái sang phải L1 AND L2 .OR Hoặc (Phép tuyển) 3 Trái sang phải L1 OR L2 .XOR Hoặc triệt tiêu 4 Trái sang phải L1 XOR L2 .EQV Tương đương 4 Trái sang phải L1 EQV L2 .NEQV Không tương đương 4 Trái sang phải L1 NEQV L2

Gộp ký tự

(25)

10 + * ** 16 / 2 cho kết 50 3.5 > 7.2 cho kết .FALSE.

Nếu a b hai biến lôgic, phép tốn a b cho kết quả: Giá trị

a b a AND b a OR b a EQV b a NEQV b

a.XOR.b a=.TRUE.,

b=.TRUE .TRUE .TRUE .TRUE .FALSE .FALSE

a=.TRUE.,

b=.FALSE .FALSE .TRUE .FALSE .TRUE .TRUE

a=.FALSE.,

b=.TRUE .FALSE .TRUE .FALSE .TRUE .TRUE

a=.FALSE.,

b=.FALSE .FALSE .FALSE .TRUE .FALSE .FALSE

Nếu ST1 ST2 là hai xâu ký tự nhận giá trị: ST1=’Hanoi’

ST2=’ Vietnam’

ST1 // ST2 cho kết ‘Hanoi Vietnam’ 1.5 HẰNG

Hằng những ký hiệu qui ước sử dụng để biểu thị giá trị có kiểu riêng Mỗi kiểu

liệu có loại tương ứng 1.5.1 Hằng nguyên

Hằng nguyên được sử dụng để biểu thị giá trị kiểu số nguyên thực Biểu diễn đơn giản rõ ràng số ngun khơng dấu có dấu Trong trường hợp ngun dương, dấu khơng bắt buộc (tuỳ ý) Ví dụ:

1000, 0, +753, 999999, 2501

là biểu diễn hệ số thập phân (cơ số 10) Các số dương có thểđược biểu diễn dạng nhị phân (binary − số 2), bát phân (octal − số 8) thập lục phân (hexa − số

16), ví dụ:

trong hệ số (binary): B'1011'

trong hệ số (octal): O'0767'

trong hệ số 16 (hexadecimal): Z'12EF'

Trong biểu diễn trên, sử dụng chữ in thường chữ in hoa Dấu nháy kép (") sử dụng thay cho dấu nháy đơn (') phân ranh giới Tuy nhiên, dạng thức không dùng với câu lệnh DATA

1.5.2 Hằng thực

(26)

− Dạng thứ viết rõ ràng, gọi dạng dấu phẩy tĩnh, bao gồm dãy số có chứa dấu chấm thập phân Nó có dấu khơng dấu Ví dụ:

0.09 37 37.0 -.6829135

Như vậy, viết thực, khơng có số phía bên trái phía bên phải dấu chấm thập phân (như 37 .0), có dấu chấm thập phân khơng thơi khơng phép

− Dạng thứ hai gọi dạng dấu phẩy động Về bao gồm số nguyên số thực dấu phẩy tĩnh (có thể có dấu khơng) sau chữ E (hoặc e), số ngun (có dấu khơng) Số ngun đứng đằng sau E số mũ 10, hàm ý 10 luỹ thừa mà sốđằng trước E phải nhân với Ví dụ:

2.0E2 (2.0 × 102 = 200.0) 2E2 (2 × 102 = 200.0)

4.12E+2 (4.12 × 10+2 = 412.0)

-7.321E-4 (7.321 × 104 = -0.0007321)

Hằng thực lưu trữ dạng luỹ thừa nhớ, không quan trọng chúng viết thực Bởi vậy, số thực có thểđược biểu diễn dạng phân số chúng biểu diễn gần Thậm chí, số ngun số thực có giá trị, chúng biểu diễn khác Ví vụ43 số nguyên, 43.0 (hoặc 43.) số thực, chúng biểu diễn khác nhớ

Phạm vi độ xác thực không cách chuẩn xác, độ xác khoảng 6−7 chữ số thập phân

1.5.3 Hằng ký tự

Hằng ký tự một chuỗi ký tự nằm cặp dấu nháy đơn (‘ ’) nháy kép (“ ”) Ngoại trừ ký tự điều khiển (chẳng hạn, #27 ESC), ký tự khác thuộc bảng mã ký tự ASCII (American Standard Code for Information Interchange − Bảng mã chuẩn dùng để trao đổi thông tin giữa thiết bị máy tính, gồm 256 ký tự, kể chữ cái, ký tự thông thường, ký tự điều khiển ký tự đồ họa) đều có thểđược sử dụng để biểu diễn ký tự Bởi ký tự bảng mã ASCII tương ứng với số thứ tự nó, nên giá trị ký tự có phân biệt chữ

thường chữ hoa Ví dụ:

“HANOI” khác với “Hanoi”, “Hai Phong” khác với “Hai phong”,…

Cũng cần phân biệt rõ khái niệm mà ta vừa đề cập với khai báo câu lệnh thuộc tính PARAMETER Khái niệm ởđây giá trị cụ thể, chúng có thểđược gán cho biến có tên Cịn khai báo PARAMETER có tên xác định tên nhận giá trị cụ thể theo khái niệm ởđây; khơng bị thay đổi giá trị q trình thực chương trình Ví dụ, xét đoạn chương trình sau:

(27)

REAL Y, Z Y = 23 Z = X + Y PRINT*, X, Y, Z END

Ởđây, X (có tên), nhận giá trị khơng đổi (là số) 12 Còn Y Z biến, Yđược gán số có giá trị 23

1.6 TÊN BIẾN VÀ TÊN HẰNG

Ta thấy vị trí nhớ có thểđược chỉđịnh tên tượng trưng (symbolic names), gọi tên biến hoặc tên hằng, như SoTien LaiSuat Tên biến, tên gồm đến 31 ký tự, phải bắt đầu chữ tiếng Anh Các ký tựđược sử dụng để cấu tạo tên biến, tên gồm 26 chữ tiếng Anh, không phân biệt chữ thường, chữ hoa, (A−Z a−z), 10 chữ số (0−9), dấu gạch dưới (_)

Ngoại trừ xâu ký tự, Fortran không phân biệt tên viết chữ thường hay chữ hoa, ví dụ MYNAME MyName Có lẽ người có truyền thống lập trình Fortran lâu năm thường viết chương trình chữ in hoa Tuy nhiên ta nên viết lẫn chữ thường chữ hoa cho dễ đọc Chẳng hạn, ta viết SoTien chắc chắn dễ hiểu viết SOTIEN. Mặt khác, Fortran 90, phiên sau này, không khống chế độ dài tên ký tự phiên cũ, nên để rõ ràng, tên viết dài tốt tên viết ngắn, mang tính gợi nhớ Chẳng hạn, nên viết SoTien thay cho cách viết đơn giản ST

Sau số ví dụ cách đặt tên biến, tên hợp lệ không hợp lệ:

Tên hợp lệ Tên không hợp lệ

X X+Y (vì chứa dấu + phép tốn)

R2D2 SHADOW FAX (vì chứa dấu cách)

Pay_Day 2A (vì ký tựđầu tiên chữ số)

ENDOFTHEMONTH OBI-WAN (vì chứa dấu − phép tốn)

Biến vị trí nhớ mà giá trị bị thay đổi trình thực chương trình Tên biến cấu tạo theo qui tắc Biến có kiểu loại liệu xác định, cho khai báo kiểu, ví dụ:

INTEGER X ! X là biến nguyên byte

REAL LaiSuat ! LaiSuat là biến thực byte

CHARACTER LETTER ! LETTER là biến ký tựđộ dài

REAL :: A = ! A là biến thực nhận giá trị khởi tạo

Chú ý rằng, biến khởi tạo khai báo nó, câu lệnh cuối ví dụ Trong trường hợp phải sử dụng dấu hai chấm kép (::) Giá trị biến khởi tạo theo cách bị thay đổi q trình chương trình thực

(28)

lỗi lúc thực chương trình (Run−time error), khó gỡ rối Ví dụ, chạy chương trình sau

đây ta nhận kết quảđúng: Real x, y, z

x = 3.0 y = 2.0 z = x / y print*, x, y, z end

Nhưng bỏ dòng thứ hai thứ ba chạy lại chương trình lỗi Run−time error xuất câu lệnh z = x/yđã tham chiếu đến biến x y chưa xác định

Biến có thểđược xác định nhiều cách, ví dụ việc khởi tạo (như ví dụ trước) việc gán giá trị cho nó, ví dụ ví dụ trước

Biến có thểđược gán giá trị ban đầu lệnh DATA sau khai báo, ví dụ: REAL A, B

INTEGER I, J

DATA A, B / 1, / I, J / 0, -1/

Câu lệnh DATA gán giá trị1 cho biến A, 2 cho biến B, 0 cho biến I1 cho biến J

Tên (kể tên biến, tên tên chương trình) chương trình phải Chẳng hạn, chương trình đặt tên TinhTien, việc khai báo biến khác tên dẫn đến lỗi

Các biến mô tả ví dụ gọi biến vơ hướng, hay biến đơn, thời điểm chúng lưu giá trị đơn Ngoài biến vơ hướng cịn có loại biến khác, chẳng hạn biến mảng Ta sẽđề cập chi tiết đến loại biến sau

1.7 QUI TẮC KIỂU ẨN

Các phiên trước Fortran có qui tắc đặt tên ngầm định gọi qui tắc kiểu ẩn (implicit type rule) Theo qui tắc này, biến bắt đầu chữ I, J, K, L, M, Nđược tựđộng hiểu biến có kiểu số nguyên (INTEGER), biến bắt đầu chữ khác, không khai báo rõ ràng, sẽđược hiểu biến thực (REAL) Để bảo đảm tính tương thích chương trình viết với phiên trước, qui tắc áp dụng ngầm định Fortran 90

Tuy nhiên, số tình huống, qui tắc kiểu ẩn dẫn đến lỗi chương trình trầm trọng sơ suất đáng tiếc đặt tên biến Giá trị thực có thểđược gán cách không cố ý cho biến nguyên, làm cho phần thập phân sau dấu chấm thập phân bị chặt cụt Ví dụ, khơng khai báo kiểu REAL cho biến LaiSuat câu lệnh

(29)

trong chương trình gán giá trị 0 cho biến LaiSuat, ngầm hiểu biến ngun

Đểđề phịng lỗi vậy, từđầu chương trình ta nên đưa vào câu lệnh sau IMPLICIT NONE

Câu lệnh xố bỏ thuộc tính qui tắc kiểu ẩn, tất biến sử dụng chương trình bắt buộc phải khai báo Đó cách lập trình tốt, có khai báo ta buộc phải để tâm đến biến ý nghĩa

Sau ta xét ví dụ giải toán chuyển động trường trọng lực

Nếu đá tung lên thẳng đứng với tốc độ ban đầu u, quãng đường dịch chuyển thẳng đứng s sau thời gian t cho công thức

2 gt ut ) t ( s

2

= , g gia tốc trọng trường Bỏ qua lực cản khơng khí, tính giá trị s, cho giá trị u t

Để lập chương trình giải tốn ta hình dung lơgic chuẩn bị chương trình sau: 1) Nhập giá trị g, u t vào máy tính

2) Tính giá trị s theo công thức cho 3) In giá trị s

4) Kết thúc

Nhìn dàn số người cho tầm thường, chí họ cho lãng phí thời gian viết Và đó, ta khơng lấy làm ngạc nhiên số người đó, người bắt đầu lập trình, lại thích làm trực tiếp máy tính, lập trình bước trước bước 1, để lúng túng trước kết nhận Thực tếđiều quan trọng, tạo cho ta thói quen phân tích tốn cách kỹ lưỡng, thiết kế chương trình có tính lơgic, chọn tên biến, kiểu biến

để khai báo cách phù hợp

Dựa theo bước ta viết chương trình sau: Ví dụ 1.4: Chuyển động trường trọng lực

PROGRAM ChuyenDongThangDung

! Chuyen dong thang dung duoi truong luc IMPLICIT NONE ! Xóa bỏ qui tắc kiểu ẩn

REAL, PARAMETER :: G = 9.8 ! Gia tốc trọng trường REAL S ! Quãng đường (m)

REAL T ! Thời gian

REAL U ! Tốc độ ban đầu (m/s) PRINT*, ' Thoi gian Quang duong' PRINT*

U = 60 T =

(30)

PRINT*, T, S

END PROGRAM ChuyenDongThangDung

Trước hết, khai báo G hằng, giá trị xác định khơng thay đổi chương trình nhận giá trị 9.8 Vì chương trình có sử dụng câu lệnh IMPLICIT NONE ta phải khai báo tất biến Bạn đọc kiểm chứng tác dụng câu lệnh cách thử bỏ qua câu lệnh khai báo biến đó (thêm dấu chấm than vào đầu dịng lệnh) chạy lại chương trình để xem Fortran phản ứng

1.8 PHONG CÁCH LẬP TRÌNH

Trên thực tế xảy tình ta cần sử dụng lại nâng cấp chương trình lập từ lâu rồi, khai thác chương trình người viết Sẽ khó khăn chương trình chẳng có lời thích Đối với chương trình mình, ta qn viết Việc tìm hiểu lại chương trình khơng có lời thích

vậy đơi làm cho ta nản chí, khơng đủ kiên nhẫn để thực

Để tránh tình trạng đó, cần phải có phong cách lập trình tốt Nghĩa chương trình phải có lời thích chỗ, đầy đủ, rõ ràng; câu lệnh nên chèn vào dấu cách hợp lệ, sử dụng hợp lý ký tự in thường in hoa; đoạn chương trình nên có dịng trắng; nên phân cấp câu lệnh để bố trí chúng cho có thụt, thị, dễ theo dõi

Chẳng hạn, chương trình viết đây, thường đưa vào lời thích mang ý nghĩa mơ tả, dịng mơ tả chương trình làm gì, biến khai báo có ý nghĩa gì,…

1.9 BIỂU THỨC SỐ

Trong chương trình ChuyenDongThangDung ví dụ 1.4 ta sử dụng dạng mã nguồn sau: U * T - G / * T **

Đây ví dụ biểu thức số biểu diễn ngơn ngữ Fortran, công thức liên kết hằng, biến (và hàm, hàm tính bậc hai) phép tốn thích hợp Nó qui tắc

để tính giá trị biểu thức đại số thông thường Trong trường hợp đây, biểu thức tính giá trịđơn nên gọi biểu thức vô hướng

Thứ tự thực phép tính biểu thức xác định thứ tựưu tiên phép toán Tuy nhiên, biểu thức có phận nằm ngoặc đơn ( ) chúng ln ln

được thực trước tiên Chẳng hạn, biểu thức 1 + * 3 cho kết 7, (1 + 2) * 3

cho kết 9 Chú ý −3**2 cho kết −9 9

(31)

1.9.1 Phép chia với số nguyên

Đối với người lập trình Fortran, vấn đề khơng đơn giản, nhiều kết nhận biểu thức nằm ngồi dựđốn họ Vấn đề chỗ,

đại lượng có kiểu số nguyên (hằng, biến biểu thức nguyên) chia cho đại lượng có kiểu số

nguyên khác, kết nhận có kiểu số nguyên, phần lẻ thập phân bị cắt bỏ Ta xét ví dụ sau

10 / 3 cho kết 3 19 / 4 cho kết 4 4 / 5 cho kết 0 -8 / 3 cho kết -2 3 * 10 / 3 cho kết 10 10 / * 3 cho kết 9

Như vậy, chia hai đại lượng nguyên cho nhau, kết nhận phần nguyên thương, phần dư bị cắt bỏ

1.9.2 Biểu thức hỗn hợp

Fortran 90 cho phép thực phép tính với biểu thức chứa tốn hạng có kiểu khác Ngun tắc chung kiểu liệu “yếu hơn” “đơn giản hơn” buộc phải chuyển đổi sang kiểu liệu “mạnh hơn” Vì kiểu số nguyên đơn giản nhất, biểu thức có tốn hạng ngun thực tốn hạng ngun phải chuyển thành tốn hạng có kiểu thực Tuy nhiên, q trình chuyển đổi thực phép tính mà không thiết áp dụng cho biểu thức Ví dụ:

10 / 3.0 cho kết 3.33333 4 / 5 cho kết 0.8

2**(-2) cho kết 0, 2**(2)=1/(2**2) = 1/4 Nhưng biểu thức

3 / / 3.0

sẽ cho kết 0.333333 3/2được tính trước, nhận giá trị nguyên 1.10 LỆNH GÁN GÁN HẰNG, GÁN BIỂU THỨC

Lệnh gán câu lệnh sử dụng phổ biến lập trình Cú pháp câu lệnh gán có dạng: vname = expr

(32)

dấu (=) câu lệnh gán hồn tồn khơng có nghĩa dấu tốn học, mà hiểu dấu gán, nên đọc vname gán giá trị expr Ví dụ, câu lệnh

X = A + B

được hiểu nội dung biến Xđược gán giá trị tổng nội dung biến A nội dung biến B Khi thực câu lệnh, máy lấy giá trị A cộng với giá trị B, kết nhận sau

đó gán cho biến X Tương tự, câu lệnh N = N +

hàm nghĩa tăng giá trị biến N lên đơn vị Đương nhiên toán học biểu thức khơng có ý nghĩa Tác động trình thực câu lệnh lấy nội dung biến N cộng với 1, gán lại cho biến N

Nếu expr không kiểu với vname, chuyển đổi sang kiểu liệu vname trước gán Có nghĩa điều dẫn đến sai số tính tốn Ví dụ, giả sửN là biến ngun, cịn X Y biến thực thì:

N = 10 / 3 (giá trị N 3) X = 10 / 3 (giá trị X 3.0) Y = 10 / 3. (giá trị Y 3.33333)

Sự vô ý lập trình nhiều lúc dẫn đến kết sai khơng đáng có Chẳng hạn, muốn tính trung bình cộng hai số (ví dụ điểm trung bình hai môn học), đặt tên biến môn

đó M1 M2 mà khơng khai báo chúng biến thực (tức máy hiểu hai biến nguyên theo qui tắc kiểu ẩn), điểm trung bình xác định câu lệnh:

TBinh = (M1 + M2) /

sẽ bị chặt cụt phần thập phân vế phải kết phép chia hai số nguyên Nếu tổng (M1+M2) không chia hết cho 2 kết nhận sai Nhưng, câu lệnh viết dạng:

TBinh = (M1 + M2) / 2.0

thì kết lại hồn tồn xác M1 M2 biến nguyên Sau số ví dụ câu lệnh gán

C = (A ** + B ** 2) ** 0.5 / (2 * A) A = P * (1 + R / 100) ** N

Câu lệnh thứ có thểđược viết cách khác sử dụng hàm thư viện SQRT (hàm lấy bậc hai) Fortran sau:

C = SQRT ( A ** + B ** ) / (2 * A)

(33)

Bởi (1/2) biểu thức lũy thừa nhận giá trị 0 phép chia hai số nguyên cho 1.11 LỆNH VÀO RA ĐƠN GIẢN

Quá trình nhận thông tin vào kết xuất thông tin máy tính gọi q trình vào liệu Dạng vào liệu đơn giản Fortran sử dụng lệnh READ* PRINT*,

được gọi vào trực tiếp Các dạng vào liệu phức tạp đề cập đến phần sau

Trong mục trước ta gặp câu lệnh với READ* PRINT*, chưa giải thích chúng Ởđây ta thấy câu lệnh thường dùng mà ta cần phải tìm hiểu

1.11.1 Lệnh vào liệu

Từ ví dụ nhận thấy biến gán giá trị cách sử dụng câu lệnh gán, chẳng hạn chương trình TinhTien:

SoTien = 1000.0 LaiSuat = 0.09

Cách làm khơng linh hoạt, muốn chạy chương trình với giá trịsố tiền gốc hoặc lãi suất khác nhau, mỗi lần ta phải thay đổi trực tiếp câu lệnh gán chương trình, sau biên dịch lại thực chương trình Thay cho cách ta sử dụng câu lệnh READ* sau:

READ*, SoTien, LaiSuat

Trong trường hợp này, chạy chương trình, máy chờ ta gõ giá trị biến từ bàn phím Các giá trị có thểđược gõ dòng, phân cách dấu cách, dấu phẩy dòng khác

Dạng tổng quát lệnh READ* sau: READ*, list

Trong list danh sách biến; có nhiều biến chúng viết cách dấu phẩy

Khi vào liệu với lệnh READ* cần ý sốđiểm sau

− Mỗi dòng liệu gõ liên tục (không dùng dấu ENTER xuống dòng) gọi ghi Nếu dòng liệu q dài, khơng hiển thịđủ dịng hình, tự động “cuộn” xuống dịng dưới, thuộc ghi

(34)

sẽđược thỏa mãn với ghi chứa giá trị: 3

Trong câu lệnh: READ*, A

READ*, B READ*, C

đòi hỏi phải đưa vào ghi, ghi chứa giá trị (tức nhập liệu dùng dấu ENTER xuống dòng sau gõ vào giá trị):

3 4 5

− Khi gặp lệnh READ mới, liệu chưa đọc ghi thời (nếu còn) bị bỏ qua, ghi khác sẽđược tìm đến để nhận liệu

− Nếu lệnh READđòi hỏi nhiều liệu số liệu chứa ghi thời

tìm đến ghi để nhận tiếp liệu Do đó, liệu khơng đủđáp ứng cho lệnh READ chương trình bị kết thúc với thơng báo lỗi

Ví dụ, câu lệnh READ*, A

READ*, B, C READ*, D

với ghi liệu đưa vào (ởđây dòng xem ghi): 1

4 7 9 10

sẽ có hiệu giống lệnh gán sau: A =

B = C = D =

Tức giá trị2, 3 ghi thứ nhất, 8 ghi thứ ba 10 ghi thứ tư, bị bỏ

qua

1.11.2 Đọc liệu từ file TEXT

(35)

100 người,… Để tránh phiền phức trường hợp vậy, Fortran cung cấp phương thức vào liệu đơn giản hữu ích, sử dụng file số liệu

Ý tưởng chỗ, trước chạy chương trình, ta cần phải chuẩn bị số liệu lưu chúng vào file riêng biệt đĩa File số liệu có thểđược tạo trình soạn thảo ghi lại dạng file TEXT (ASCII file) với tên file đó, chẳng hạn SOLIEU.TXT Khi chạy chương trình, máy tìm đến file nhận số liệu từđó Muốn vậy, thay cho câu lệnh READ*, ta sử dụng hai câu lệnh có chức tham chiếu đến file đọc liệu từ file Để tiện trình bày, ta xét ví dụđơn giản sau Giả sử ta có file số liệu với tên SOLIEU.TXT mà nội dung gồm sốở dịng file:

3

Bây ta gõ chương trình sau vào máy chạy thử: PROGRAM ThuFile

REAL A, B, C

OPEN(1, FILE = 'SOLIEU.TXT') ! Mở file READ(1, *) A, B, C ! Đọc số liệu từ file PRINT*, A, B, C

END

Câu lệnh OPEN kết nối số với file SOLIEU.TXT đĩa Số gọi UNIT, mang hàm nghĩa thị số hiệu file (hay kênh vào/ra) Câu lệnh READởđây (khác với lệnh READ*) định hướng cho chương trình tìm đọc số liệu file kết nối với UNIT 1 Thông thường số UNIT nhận giá trị khoảng 19999

1.11.3 Lệnh kết xuất liệu

Lệnh PRINT* câu lệnh thuận tiện cho việc kết xuất thông tin lượng liệu khơng lớn Thơng thường sử dụng trình xây dựng, phát triển chương trình, đưa kết tính tốn trung gian để theo dõi tiến trình làm việc chương trình Dạng tổng quát sau:

PRINT*, list

Trong list có thể danh sách hằng, biến, biểu thức xâu ký tự, viết cách dấu phẩy (,) Xâu ký tự phải đặt cặp dấu nháy đơn (‘ ’) dấu nháy kép (“ ”) Nếu list danh sách rỗng lệnh có dạng đơn giản PRINT* có ý nghĩa chèn thêm dịng trống Ví dụ:

PRINT*

(36)

− Mỗi câu lệnh PRINT* tạo ghi Nếu nội dung ghi dài “cuộn” xuống dòng

−Đối với số thực, tùy theo độ lớn giá trị số in mà chúng có thểđược biểu diễn dạng dấu phẩy tĩnh dấu phẩy động Nếu muốn in dạng cầu kỳ, có qui cách, ta sử dụng lệnh định dạng FORMAT. Ví dụ, để in số123.4567 dạng dấu phẩy tĩnh cột, với chữ số

sau dấu chấm thập phân, ta viết: X = 123.4567

PRINT 10, X

10 FORMAT( F8.2 )

Lệnh định dạng FORMAT cho phép bố trí khn mẫu in theo qui cách phần dấu ngoặc đơn Trong ví dụ trên, muốn in giá trị biến X kèm theo thích hợp lý ta có thểđưa thêm vào ký tự Chẳng hạn, thay cho câu lệnh ta viết:

10 FORMAT( “Gia tri bien X = ”, F8.2 )

Hằng ký tự phải đặt cặp dấu nháy đơn, dấu nháy kép Ta sẽđề cập chi tiết đến câu lệnh mục sau

Lệnh PRINT* cũng có thểđược dùng để in thơng báo (hằng ký tự) dài q dịng cách sử dụng ký tự nối dịng Ví dụ:

PRINT*, 'Day la cau thong bao duoc & &viet bang lenh PRINT co noi dong'

1.11.4 Kết xuất máy in

Nếu muốn kết xuất máy in, ta cần đặt tham sốFILE=’PRN’ câu lệnh OPEN kết hợp với việc sử dụng lệnh WRITE Ví dụ:

OPEN (2, FILE = 'prn' ) WRITE(2, *) 'In may in' PRINT*, 'In man hinh'

Chú ý lệnh WRITE trường hợp phải gắn kết với số hiệu file UNIT lệnh OPEN. Lệnh tổng quát lệnh PRINT Ta làm quen với câu lệnh nội dung sau 1.12 SỬ DỤNG HÀM TRONG FORTRAN

Trên ta gặp trường hợp tính bậc hai số dương hàm thư viện SQRT Fortran Đó nhiều hàm có sẵn trình biên dịch cung cấp Hệ thống hàm (và hàm người dùng xây dựng bổ sung thêm) lập thành thư viện hàm (hay gọi hàm thư viện), cho phép ta sử dụng chúng “hộp đen” mà không cần biết chúng

được xây dựng Mỗi hàm thực chức tính tốn khác (như

(37)

trong biểu thức Khi tính biểu thức, hàm sẽđược thực theo trình tự thuật tốn xây dựng giá trị tính hàm thay vị trí tham chiếu đến hàm

Ví dụ, xét đoạn chương trình sau: REAL X, Y

X = 16.0

Y = 5.6 + SQRT(X) PRINT*, X, Y END

Trong chương trình này, để tính giá trị Y, cần phải tính SQRT(X).X = 16.0 nên hàm SQRT(X) = SQRT(16.0) cho kết 16.0 = 4.0 Do đó, Y = 5.6 + 4.0 = 9.6 Mặc dù ta hoàn toàn khơng biết cách tính bậc hai mà hàm SQRT thực Và ta sử dụng hàm SQRTđể tính bậc hai số X thừa nhận tính đắn, xác

Fortran cung cấp cho ta thư viện hàm phong phú Để tiện sử dụng trình bày

các phần sau, bảng 1.6 nêu số hàm thông dụng

Khi sử dụng hàm thư viện ta cần đặc biệt ý đến tính chúng Ví dụ, hàm INT NINT sử dụng đểđổi số thực thành số nguyên, hàm INT cắt bỏ phần thập phân hàm NINT làm tròn số thực đến số nguyên gần nhất:

INT(5.3) NINT(5.3) INT(5.8) NINT(5.8) INT(5.3) 5 NINT(5.3) 5 INT(5.8) 5 NINT(5.8) 6

Bảng 1.6 Một số hàm thư viện thường dùng Fortran

Tên hàm

và lời gọi hàm Chức hàm liệKiu cểu dủa đốữ i số

Kiểu dữ

liệu kết quả

INT (X) Chuyển số X thành số nguyên sau chặt cụt phần thập phân

REAL INTEGER NINT (X) Làm tròn số X đến số nguyên gần

nhất

REAL INTEGER REAL (X) Chuyển số nguyên X thành số

thực INTEGER REAL

ABS (X) Tìm giá trị tuyệt đối X REAL REAL IABS (X) Tìm giá trị tuyệt đối X INTEGER INTEGER SQRT (X) Tính bậc hai X REAL REAL

EXP (X) Tính eX REAL REAL

ALOG (X) Tính lnX (logarit tự nhiên) REAL REAL ALOG10 (X) Tính lgX (logarit thập phân) REAL REAL

SIN (X) Tĩnh Sine X REAL REAL

COS (X) Tính Cosine X REAL REAL

TAN (X) Tính Tang X REAL REAL

MOD (X,Y) Tính phần dư phép chia hai số nguyên X/Y

(38)

X1, ,XN

MIN0(X1, ,XN) Tìm giá trị nhỏ dãy số

X1, ,XN

INTEGER INTEGER AMAX1(X1, ,XN) Tìm giá trị lớn dãy số

X1, ,XN

REAL REAL AMIN1(X1, ,XN) Tìm giá trị nhỏ dãy số

X1, ,XN

REAL REAL

Hàm REALđược sử dụng đểđổi số nguyên thành số thực Nếu biến TONG N biến nguyên cịn T_BINH biến thực, hai câu lệnh sau cho kết hồn tồn khác nhau:

T_BINH = TONG / N

T_BINH = REAL(TONG)/REAL(N)

Những hàm địi hỏi có đối số, thấy bảng 1.6, có hàm địi hỏi hai đối số nhiều Ví dụ, hàm MODđịi hỏi hai đối số, hàm MAX0, MIN0, AMAX1, AMIN1 lại có số lượng đối số lớn hai

Ví dụ 1.5 Giả sử A, B, C ba đỉnh tam giác Ký hiệu AB, AC, BC cạnh tam giác, ALFA góc kẹp hai cạnh AB AC Cho biết độ dài cạnh AB, AC sốđo

độ góc ALFA, tính độ dài cạnh BC theo cơng thức: BC2 = AB2 + AC2− 2.AB.AC.Cos(Alfa)

Viết chương trình nhập vào độ dài cạnh AB, AC góc ALFA (độ) tính độ dài cạnh BC

Ta có chương trình sau: REAL AB, AC, BC, ALFA REAL PI

PI = 4.0*ATAN (1.0)

PRINT*,’Cho dai cac canh AB, AC: ‘ READ*, AB,AC

PRINT*,’Cho so goc (do) giua AB va AC: ’ READ*, ALFA

BC = SQRT (AB**2 + AC**2 2*COS(ALFA*PI/180.0) ) PRINT*,’Do dai canh BC = ‘, BC

END

Trong chương trình trên, hàm ATAN để tính Arctang Vì Tang góc π/4 nên Arctang của π/4

(39)

2

2

2 )

(x e x

f = −

π

Biểu thức ước lượng giá trị hàm viết ngôn ngữ Fortran có dạng: F = 1.0/SQRT(2.0*PI)*EXP(0.5*X*X)

BÀI TẬP CHƯƠNG

1.1 Hãy cho biết tên biến tên viết sai theo qui ước Fortran, sao: (a) A2 (b) A.2 (c) 2A (d) 'A'ONE (e) AONE (f) X_1 (g) MiXedUp (h) Pay Day (i) U.S.S.R (j) Pay_Day (k) min*2 (l) PRINT

1.2 Hãy xác định xem sau viết đúng, viết sai theo qui

ước Fortran, sao: (a) 9,87 (b) (c) 25.82 (d) –356231 (e) 3.57*E2 (f) 3.57E2.1 (g) 3.57E+2 (h) 3,57E–2

1.3 Hãy viết biểu thức sau ngôn ngữ Fortran:

(a) ax2 +bx +c=0; (b) ax2 +bx+c>0; (c) ax2 +bx+c<0; (d) ax2 +bx +c≠0; (e) c

bx

ax2 + + ≥

0; (f) ax2 +bx+c≤0

1.4 Tìm chỗ sai đoạn chương trình sau: INTEGER*1 A, N

INTEGER*2 B, M REAL X

LOGICAL L A = 12.0 N = 150 B = 54.4 M = 33456 L = TRUE

1.5 Hãy gõ đoạn chương trình sau vào máy, chạy tính thử khảo sát thơng báo lỗi (ERROR) dịch chương trình sửa lại cho đúng:

PROGRAM Dread_ful REAL: A, B, X

X:= Y = 6,67 B = X \ Y

PRINT* 'The answer is", B END

1.6 Lập chương trình nhập vào hai số thực A B, tính tổng, hiệu, tích thương chúng In kết lên hình với dịng thích phù hợp Hãy khảo sát điều xảy thực phép chia cho số

(40)

1.8 Cho trước giá trị ba biến thực A=2, B=3, C=5 hai biến nguyên I=2, J=3 Hãy cho biết giá trị biểu thức sau chúng tính chương trình Fortran:

1) A*B + C; 2) A*(B + C); 3) B/C*A; 4) B/(C * A); 5) A/I/ J; 6) I/J/A; 7) A*B**I/A ** J * 2; 8) C + (B / A) ** / B * 2.; 9) A ** B ** I; 10) −B** A ** C; J / (I / J)

1.9 Nhiệt độ vịθđược xác định công thức θ = T

p

C / R

p 1000

⎟⎟ ⎠ ⎞ ⎜⎜ ⎝

⎛ , đó T (oC) p (mb)

là nhiệt độ áp suất ban đầu phần tử khí, R/Cp≈0.288 Hãy lập chương trình nhập vào giá trị

nhiệt độ áp suất ban đầu phần tử khí tính nhiệt độ vị 1.10 Giả sử có khai báo sau:

REAL P1, X, Y

INTEGER MAXI, A, B, I

PARAMETER (P1 = 3.14159, MAXI = 1000)

Hãy tính giá trị câu lệnh hợp lệ đây, đồng thời câu lệnh không hợp lệ, Cho A=3, B=4 X=1.0

I = A * B

I = (990 MAXI) / A I = A*Y

x = pi*y I = A/B X = A / B X = A * (A/ B) I = B /

I = A * (990 — MAXI) I = (MAXI — 990) / A X = A / Y

I = PI*A x = pi/y I = B/A

I = (MAXI — 990) * A L = A *

I = A * MAXI — 990)

1.11 Cho A, B, C X tên bốn biến thực (REAL), I, J K tên ba biến nguyên (INTEGER) Hãy sửa câu lệnh cho phù hợp với qui tắc biểu diễn biểu thức số học ngôn ngữ Fortran

(41)

1.12 Viết chương trình xác định số lần đập tim đời người Chương trình cho phép tính với nhịp đập tim (ví dụ 72 lần/phút) với tuổi thọ

của người (ví dụ 75 tuổi) Lấy số ngày năm 365.25 ngày

1.13 Thời gian bay (t − giây) độ cao (h − mét) đạt viên đạn pháo xác định theo công thức:

θ

cos v

S t=

2

2

gt vt h= −

trong S (m) khoảng cách từ nơi bắn đến mục tiêu; v (m/s) vận tốc ban đầu viên đạn; θ

(radian) góc nâng nịng pháo; g (m/s2) gia tốc trọng trường Cho g = 9.8 m/s2 Hãy viết

chương trình nhập vào khoảng cách đến mục tiêu, góc nâng nòng pháo vận tốc ban đầu viên đạn tính thời gian bay độ cao đạt viên đạn

1.14 Biệt thự gia đình hình chữ nhật có kích thước XN YN Biệt thự

được xây dựng khu đất hình chữ nhật có cạnh song song với biệt thự có kích thước XD YD Ngồi biệt thự, khu đất cịn có vườn hoa hình trịn bán kính RH Khoảng trống lại khu đất cỏ Hãy viết chương trình nhập vào giá trị hợp lệ kích thước biệt thự, khu đất vườn hoa tính xem người cắt cỏ cắt m2/s phải thời gian để cắt hết cỏ khu đất

1.15 Viết chương trình nhập vào tử số mẫu số hai phân số tính tổng, hiệu, tích, thương chúng In kết dạng phân số giá trị phần trăm phân số kết

1.16 Viết chương trình đọc vào giờ, phút, giây đổi biểu diễn dạng số thập phân (ví dụ XX giờ, YY phút, ZZ giây sẽđược đổi thành HH.TTTT giờ)

1.17 Viết chương trình nhập giá trị ba điện trở mạch điện mắc song song tính điện trở tương đương mạch theo công thức:

3

1 1 1 1

R R R

Rtd = + +

1.18 Bộ số nguyên dương m, n, p thỏa mãn điều kiện m2 + n2 = p2được gọi bộ ba số Pitago

(ví dụ, ba số 3, 4, số Pitago), ba số thỏa mãn điều kiện ba cạnh tam giác vuông, m n hai cạnh góc vng, p cạnh huyền Cho hai số nguyên dương x y, với x > y, tạo số Pitago theo công thức sau:

m = x2− y2

(42)

Viết chương trình nhập vào hai số nguyên dương thành lập số Pitago theo công thức

1.18 Tốc độ suy giảm nhiệt độ theo phương thẳng đứng (gradient thẳng đứng nhiệt độ) lớp khí lấy gần 0.6oC/100m Viết chương trình xác định nhiệt

độ khí ởđộ cao h (m) biết nhiệt độở mực nước biển (h=0) T (OC)

1.19 Hãy biểu thị dạng câu lệnh Fortran nội dung sau: (a) Thêm vào giá trị biến I lưu kết vào ô nhớ biến I

(b) Lấy luỹ thừa I cộng với J lưu kết vào ô nhớ I

(c) Chia tổng A B cho tích C D lưu vào nhớ biến X 1.20 Viết chương trình tính giá trị biểu thức sau:

A=( )( )

x 19238

5 172 15

20345 x cos c

b sin x

+ + −

+ ,

trong đó: x nhập từ bàn phím; b=2x−31.769; c=lg(x4+5x)+ln(x2+5b)

1.21 Viết chương trình nhập vào toạ độ ba điểm A(x1,y1), B(x2,y2), C(x3,y3) tính tích vơ

hướng vectơ AB, AC

1.22 Sử dụng trình soạn thảo Fortran (hoặc trình soạn thảo bất kỳ) tạo file TEXT có tên SOLIEU.TXT với nội dung file sau:

23 12.5 65.2 21 67 89 34 56 76 32 45.6

54.6 67.8 21.3

Sau viết chương trình đọc file số liệu theo yêu cầu: Đọc giá trị thứ thứ ba dòng gán cho biến A, B; Đọc giá trị thứ hai, thứ ba thứ tưở dòng gán cho biến C, D, E; Đọc hai giá trịở dòng giá trị thứ dòng gán cho biến X, Y, Z In kết nhận

(43)

CHƯƠNG CÁC CÂU LỆNH CƠ BẢN CỦA FORTRAN

Trong chương trước làm quen với số câu lệnh Fortran, lệnh gán, lệnh vào đơn giản với READ* PRINT*, lệnh mở file OPENđể nhận liệu từ file TEXT kết xuất thông tin máy in, lệnh định dạng FORMAT, Với câu lệnh đó, ta viết

được số chương trình đơn giản Chương nghiên cứu câu lệnh phức tạp 2.1 LỆNH CHU TRÌNH (DO LOOPS)

Khi viết chương trình, ta bắt gặp tình huống, nhiều câu lệnh phải thực lặp lại nhiều lần giống Chẳng hạn, muốn in 10 số nguyên liên tiếp, lần in số, ta phải dùng đến 10 câu lệnh in Điều làm cho ta nhiều lúc cảm thấy bất tiện Tuy nhiên, thay cho cách làm đây, Fortran hỗ trợ cấu trúc câu lệnh đơn giản hiệu Đó câu lệnh chu trình, hay chu trình lặp xác định Cú pháp câu lệnh có dạng sau

Dạng 1:

DO m bdk = TriDau, TriCuoi [, Buoc] Các_câu_lệnh

m Câu_lệnh_kết_thúc Dạng 2:

DO m bdk = TriDau, TriCuoi [, Buoc] Các_câu_lệnh

m CONTINUE Dạng 3:

DO bdk = TriDau, TriCuoi [, Buoc] Các_câu_lệnh

END DO

Trong đó: bdk, TriDau, TriCuoi, Buoc phải có kiểu liệu; m nhãn câu lệnh kết thúc chu trình, trường hợp khơng thể sử dụng câu lệnh kết thúc vậy, thay câu lệnh m CONTINUE nhưở dạng Nếu TriDau < TriCuoi Buoc phải số dương, ngược lại TriDau > TriCuoi Buoc phải số âm Nếu Buoc=1 bỏ qua Buoc

Cấu trúc dạng dạng Fortran 77 phiên trước đó, chúng tương thích với Fortran 90 Mặc dù vậy, sốđặc điểm mở rộng câu lệnh chu trình Fortran 90 (mà ta sẽđề cập phần sau), người ta sử dụng cấu trúc

Tập Các_câu_lệnh nằm DO m Câu_lệnh_kết_thúc

hoặc

(44)

hoặc ENDDO

là câu lệnh thực lặp lặp lại Số lần lặp lại xác định bởi: Số lần lặp = MAX { (TriCuoi − TriDau + Buoc) / Buoc, }

Tác động lệnh chu trình mơ tả hình 2.1 Có thể tóm tắt tác động qua bước sau

1) Bắt đầu chu trình bdkđược gán giá trị TriDau

2) Sau chương trình thực biểu thức so sánh bdk<=TriCuoi bdk>=TriCuoi: a) Nếu biểu thức cho kết TRUE (đúng):

a.1) Tiếp tục thực Các_câu_lệnh, kể Câu_lệnh_kết_thúc, nằm chu trình tăng giảm bdk lượng trị tuyệt đối Buoc

a.2) Quay thực bước 2)

b) Nếu biểu thức cho kết FALSE (sai) kết thúc chu trình

a) Trường hợp TriDau<=TriCuoi b) Trường hợp TriDau>=TriCuoi Hình 2.1 Sơđồ khối mơ tả tác động lệnh chu trình DO

Ta nhận thấy, tác động chu trình thực hiện lặp lặp lại Các_câu_lệnh, kể Câu_lệnh_kết_thúc Mỗi lần giá trị bdk thay đổi phù hợp với Buoc, TriDau TriCuoiđược giữ nguyên vòng lặp kết thúc Do đó, phạm vi vịng lặp, tức Các_câu_lệnh Câu_lệnh_kết_thúc, tuyệt đối không xuất câu lệnh làm thay đổi giá trị bdk, TriDau TriCuoi, không dẫn đến lỗi khơng lường trước

Ví dụ 2.1 Chương trình sau tính tổng số nguyên liên tiếp từN1đến N2, N1 N2được nhập vào từ bàn phím

INTEGER N1, N2, TONG, I

(45)

READ*, N1, N2 TONG = DO I = N1,N2,1 TONG = TONG + I PRINT*, I

ENDDO

PRINT '(" TONG=",I5)', TONG END

Khi chạy chương trình, số nguyên liên tiếp từN1đến N2 sẽđược lên hình cuối thơng báo kết tổng số từ N1 đến N2 Các câu lệnh

PRINT '(A\)', ' CHO GIA TRI N1, N2 (N1<=N2):'

PRINT '(" TONG=",I5)', TONG

đã chứa lệnh định dạng FORMAT Tuy nhiên, cảm thấy xa lạ, thay phần

định dạng dấu (*) Trong câu lệnh

DO I = N1,N2,1

số cuối giá trị Buoc, có thểđược bỏ qua mà khơng ảnh hưởng đến kết Nhưng thay −1 nhập N1 N2 cần phải lưu ý N1>=N2, không nhận kết

bất ngờ (!?), số lần lặp Các câu lệnh

DO I = N1,N2,1 TONG = TONG + I PRINT*, I

ENDDO

cũng có thểđược thay câu lệnh sau DO 100 I = N1, N2

TONG = TONG + I 100 PRINT*, I

Trong trường hợp này, câu lệnh 100 PRINT*, I

là câu lệnh kết thúc chu trình, Buoc có giá trị nên ta bỏ qua Ta dùng câu lệnh CONTINUEđể kết thúc chu trình sau:

DO 100 I = N1, N2 TONG = TONG + I PRINT*, I

100 CONTINUE

(46)

Ví dụ 2.2 Chương trình tính bậc hai số a theo phương pháp Newton có thểđược mơ tả

như sau:

1) Nhập vào sốa

2) Khởi tạo x 1 (gán giá trị cho x 1) 3) Lặp lại 6 lần bước sau đây:

a) Thay x (x + a/x)/2 b) In giá trị x

4) Kết thúc chương trình

Mã nguồn chương trình sau:

PROGRAM Newton ! Tinh can bac hai bang pp Newton REAL A ! Số lấy bậc hai

INTEGER I ! Biến đếm phép lặp

REAL X ! Giá trị gần bậc hai a WRITE( *,*) ' Cho so se lay can bac hai: '

READ*, A PRINT*

X = ! Khởi tạo giá trị ban đầu x (??) DO I = 1,

X = (X + A / X) / PRINT*, X ENDDO PRINT*

PRINT*, 'Can bac cua ‘,a,’ tinh theo F90 la:',& SQRT(A)

END

Khi chạy chương trình, hình xuất 6 lần giá trị X Giá trịở dòng thứ6được xem gần bậc hai a tính phương pháp lặp Newton, cịn giá trị in dòng cuối bậc hai a tính hàm thư viện SQRT Fortran Giữa chúng có khác nhau; a lớn khác nhiều Trong trường hợp ta tăng số lần lặp lại cách thay số6 dòng lệnh DO I = 1, 6 số lớn chạy lại chương trình Việc so sánh kết nhận sau lần thay đổi dòng lệnh giúp ta hiểu rõ ý nghĩa vòng lặp

Chú ý: Nói chung Fortran cho phép biến bdk, TriDau, TriCuoi, Buoc nhận kiểu liệu số nguyên số thực Tuy nhiên ta không nên dùng kiểu liệu thực, số thực biểu diễn

dạng gần đúng, gây nên sai số không lường trước 2.2 LỆNH RẼ NHÁNH VỚI IF

Cấu trúc rẽ nhánh kiểu cấu trúc phổ biến ngơn ngữ lập trình Trong Fortran, cấu trúc rẽ nhánh cho đa dạng Sau ta xét trường hợp

2.2.1 Dạng

(47)

Hình 2.2 Cấu trúc IF dạng 1

Trong Câu_lệnh câu lệnh thực khơng thể câu lệnh có cấu trúc khác, nhưIF, DO,BThuc_Logic điều kiện rẽ nhánh Tác động câu lệnh IF là, BThuc_Logic nhận giá trị .TRUE. (đúng) chương trình thực Câu_lệnh sau đó, ngược lại, BThuc_Logic nhận giá trị.FALSE. (sai) Câu_lệnh sẽ bị bỏ qua chương trình tiếp

tục với câu lệnh khác sau IF Sơđồ khối mô tả tác động

được cho hình 2.2

Ví dụ 2.3 Hãy đọc vào số cho biết số dương, số âm hay số Chương trình có thểđược viết sau

! Vi du ve lenh re nhanh REAL X

PRINT '(A\)',' CHO MOT SO:' READ*, X

IF (X > 0) PRINT *, ' DAY LA SO DUONG' IF (X < 0) PRINT *, ' DAY LA SO AM' IF (X == 0) PRINT *, ' DAY LA SO 0' END

Nhưđã thấy, cấu trúc này, BThuc_Logic nhận giá trị.TRUE. (đúng) có câu lệnh sau thực

2.2.2 Dạng

IF (BThuc_Logic) THEN Các_câu_lệnh

END IF

Về nguyên tắc, tác động câu lệnh hoàn toàn giống với cấu trúc dạng Sự khác chúng chỗ, cấu trúc dạng 1, điều kiện thỏa mãn (BThuc_Logic nhận giá trị .TRUE.) có câu lệnh sau IF thực hiện, trường hợp này, BThuc_Logic nhận giá trị.TRUE. có nhiều câu lệnh nằm IF THEN END IF thực (Các_câu_lệnh hàm nghĩa có nhiều câu lệnh)

Ví dụ 2.4 Viết chương trình nhập vào hai số thực, chúng đồng thời khác tính tổng, hiệu, tích, thương chúng

REAL X, Y, TONG, HIEU, TICH, THUONG PRINT*, ‘ CHO SO THUC:’

READ*, X, Y ! Đọc số X, Y từ bàn phím

IF (X /= 0.AND.Y /= 0) THEN

! X Y đồng thời khác TONG = X + Y

HIEU = X Y TICH = X * Y THUONG = X / Y

(48)

PRINT*,’ HIEU CUA ’,X,’ VA ‘,Y,’ LA:’,HIEU PRINT*,’ TICH CUA ’,X,’ VA ‘,Y,’ LA:’,TICH PRINT*,’ THUONG CUA ’,X,’ VA ‘,Y,’ LA:’,& THUONG

END IF

IF (X == 0.OR.Y == 0) THEN ! Một hai số = PRINT*,’ MOT TRONG HAI SO VUA NHAP = 0’ END IF

END

2.2.3 Dạng

IF (BThuc_Logic) THEN Các_câu_lệnh_1 ELSE

Các_câu_lệnh_2 END IF

Khác với hai cấu trúc trên, cấu trúc việc thực chương trình rẽ hai “nhánh”: Nếu BThuc_Logic nhận giá trị.TRUE. chương trình thực Các_câu_lệnh_1, ngược lại, chương trình thực Các_câu_lệnh_2 Sơ đồ khối mô tả tác động cấu trúc cho hình 2.3

Ví dụ 2.5 Viết chương trình nhập vào từ bàn phím ba số

thực Nếu ba sốđó thỏa mãn điều kiện ba cạnh tam giác tính diện tích tam giác Ngược lại đưa

thông báo “BA SO NAY KHONG PHAI LA CANH

CUA TAM GIAC” PROGRAM TAM_GIAC

REAL A,B,C ! Ba số nhập vào REAL P,S ! Nửa chu vi Diện tích LOGICAL L1

LOGICAL L2

PRINT*, ' CHO SO THUC:' READ*, A,B,C

L1 = A>0.AND.B>0.AND.C>0 ! Ba số Dương L2 = A+B>C.AND.B+C>A.AND.C+A>B

!Ba số phải thỏa mãn bất đẳng thức tam giác IF (L1.AND.L2) THEN ! Thỏa mãn điều kiện Tam giác P = (A+B+C)/2

S = SQRT(P*(P-A)*(P-B)*(P-C))

PRINT*,' DIEN TICH TAM GIAC = ',S ELSE ! Không thỏa mãn điều kiện Tam giác

PRINT*,"BA SO NAY KHONG PHAI LA CANH & &CUA TAM GIAC"

END IF END

(49)

Trong chương trình ta sử dụng hai biến lơgic L1, L2để xác định ba số nhập vào có thỏa mãn điều kiện ba cạnh tam giác hay không Cách dùng biến kiểu có ích, trường hợp phức tạp giúp ta gỡ rối chương trình nhanh chóng xác Hơn nữa, viết chương trình trơng sáng sủa

2.2.4 Dạng

IF (BThuc_Logic_1) THEN Các_câu_lệnh_1

ELSE IF (BThuc_Logic_2) THEN Các_câu_lệnh_2

ELSE IF (BThuc_Logic_3) THEN Các_câu_lệnh_3

ELSE

Các_câu_lệnh_n END IF

Cấu trúc gọi cấu trúc khối IF (Block IF) Tác động cấu trúc mơ tả

trên hình 2.4 Trước hết, chương trình kiểm tra BThuc_Logic_1 Nếu BThuc_Logic_1 nhận giá trị .TRUE Các_câu_lệnh_1 thực hiện; BThuc_Logic_1 nhận giá trị .FALSE. chương trình kiểm tra đến BThuc_Logic_2. Nếu BThuc_Logic_2 nhận giá trị .TRUE. Các_câu_lệnh_2 thực hiện; BThuc_Logic_2 nhận giá trị FALSE chương trình

kiểm tra BThuc_Logic_3,… Quá trình tiếp diễn tất BThuc_Logic nhận giá trị .FALSE. chương trình thực Các_câu_lệnh_n. Nếu Các_câu_lệnh_*

giai đoạn q trình thực hiện, chương trình thoát khỏi cấu trúc IF chuyển

điều khiển đến câu lệnh sau END IF, ngoại trừ trường hợp Các_câu_lệnh_* có lệnh chuyển điều khiển GOTOđến vị trí khác chương trình

Hình 2.4 Cấu trúc IF dạng

(50)

sau: Loại xuất sắc TBCHT >=9; Loại giỏi 9<TBCHT<=8; Loại 8<TBCHT<=7; Loại trung bình 7<TBCHT<=5 loại yếu TBCHT<5

PROGRAM XEPLOAI_1 INTEGER DIEM

WRITE (*,'(A\)') ' CHO DIEM TBCHT: ' READ*, DIEM

IF (DIEM < 0.OR.DIEM > 10) THEN PRINT*, ‘ DIEM KHONG HOP LE’ STOP

! Dừng chương trình điểm khơng hợp lệ

ELSE IF (DIEM >= 9) THEN PRINT*,' LOAI XUAT SAC' ELSE IF (DIEM >= 8) THEN PRINT*,' LOAI GIOI' ELSE IF (DIEM >= 7) THEN PRINT*,' LOAI KHA' ELSE IF (DIEM >= 5) THEN PRINT*,' LOAI TRUNG BINH' ELSE

PRINT*,' LOAI YEU' END IF

END

Chương trình viết cách khác sau PROGRAM XEPLOAI_2

INTEGER DIEM

WRITE (*,'(A\)') ' CHO DIEM TBCHT: ' READ*, DIEM

IF (DIEM < 0.OR.DIEM < 10) THEN PRINT*, ‘ DIEM KHONG HOP LE’ STOP

END IF

IF (DIEM >= 9) PRINT*,' LOAI XUAT SAC'

IF (DIEM >= 8.AND.DIEM < 9) PRINT*,' LOAI GIOI' IF (DIEM >= 7.AND.DIEM < 8) PRINT*,' LOAI KHA' IF (DIEM >= 5.AND.DIEM < 7)PRINT*,' LOAI TR.BINH' IF (DIEM < 5) PRINT*,' LOAI YEU'

END

Trong hai chương trình trên, lệnh STOP làm kết thúc (dừng hẳn) chương trình giá trị DIEM nhập vào không hợp lệ (DIEM < 0 DIEM > 10) Câu lệnh WRITE hàm chứa

định dạng FORMAT (‘(A\)’) có tác dụng giữ cho trỏ hình khơng nhảy xuống dịng mà nằm sau ký tự ‘CHO DIEM TBCHT: ‘ Rõ ràng, sử dụng cấu trúc khối IF

(51)

2.2.5 Lệnh nhảy vô điều kiện GOTO

Đây câu lệnh sử dụng phổ biến Fortran 77 phiên trước Khi lập trình với Fortran 90 lệnh GOTO sử dụng gọi “sự phá vỡ cấu trúc” Mặc dù vậy, câu lệnh giúp người lập trình cảm thấy nhẹ nhàng gặp phải tình khó xử

Cú pháp câu lệnh GOTO có dạng sau: GOTO m

Trong m nhãn câu lệnh sẽđược chuyển điều khiển tới chương trình Khi gặp lệnh GOTO, chương trình chuyển điều khiển tới câu lệnh có nhãn m Nếu chương trình khơng có câu lệnh có nhãn m lỗi xuất Hơn nữa, câu lệnh chuyển điều khiển tới (câu lệnh có nhãn m) khơng phép nằm vịng kiểm sốt lệnh chu trình DO cấu trúc rẽ nhánh IF Chẳng hạn, trường hợp sau không phép:

GOTO 123

DO I = 1, N

123 X = X + Y

END DO Hoặc:

GOTO 456

IF (L1.AND.L2) THEN

456 A = B * C

END IF

Nhưng dùng lệnh GOTO để khỏi chu trình lặp cấu trúc rẽ nhánh đó, chẳng hạn:

DO I = 1, N

GOTO 123

END DO 123 X = X + Y Hoặc

IF (L1.AND.L2) THEN

(52)

END IF 456 A = B * C

Sau ví dụ minh họa tác động lệnh GOTO Cho giá trị biến lôgic L1 L2 Nếu L1=.TRUE. gán I=1, J=2; L1=.FALSE. cịn L2=.TRUE. gán I=2, J=3; L1 L2đều nhận giá trị.FALSE. gán I=3, J=4. Khi đó, đoạn chương trình:

IF (L1) THEN I =

J =

ELSE IF (L2) THEN I =

J = ELSE I = J = END IF

có thểđược thay đoạn chương trình sau sử dụng lệnh GOTO IF (.NOT.L1) GOTO 10

I = J = GOTO 30

10 IF (.NOT.L2) GOTO 20 I =

J = GOTO 30 20 I = J =

30 CONTINUE

2.2.6 Lệnh IF số học

IF (BThuc_SoHoc) m1, m2, m3

Trong BThuc_SoHoc biểu thức số học, có kiểu nguyên thực; m1, m2,

m3 nhãn câu lệnh có chương trình

Người ta gọi cấu trúc IF này IF số học, quyết

định rẽ nhánh phụ thuộc vào dấu

BThuc_SoHoc Tác động cấu trúc

mơ tả hình 2.5

Trước hết chương trình tính giá trị

BThuc_SoHoc Nếu BThuc_SoHoc nhận

giá trị âm, chương trình chuyển điều khiển tới

câu lệnh có nhãn m1; BThuc_SoHoc nhận

giá trị 0, chương trình chuyển điều khiển tới câu lệnh có nhãn m2; BThuc_SoHoc nhận giá trị dương, điều khiển chuyển tới câu

(53)

lệnh có nhãn m3. Hai ba nhãn m1, m2, m3 trùng nhau, có nghĩa hai nhánh điều khiển chuyển đến câu lệnh Tuy nhiên câu lệnh có nhãn m1, m2, m3 khơng phép nằm vịng kiểm sốt lệnh chu trình DO cấu trúc rẽ nhánh khác Cũng lệnh GOTO, lệnh IF số học sử dụng lập trình với Fortran 90

Ví dụ 2.7 Nhập vào số nguyên xác định xem sốđó nhỏ hơn, lớn hay 50 Ta có chương trình sau

INTEGER N

PRINT*, ' CHO MOT SO NGUYEN ' READ*, N

IF (N50) 10, 20, 30

10 PRINT*,' SO NAY NHO HON 50' GOTO 40

20 PRINT*,' SO NAY BANG 50' GOTO 40

30 PRINT*,' SO NAY LON HON 50' 40 CONTINUE

END

Nếu ta quan tâm đến việc số nhập vào có lớn 50 hay khơng, cấu trúc rẽ nhánh

cần chuyển điều khiển đến hai nhánh Khi chương trình viết lại thành: INTEGER N

PRINT*, ' CHO MOT SO NGUYEN ' READ*, N

IF (N50) 10, 10, 30

10 PRINT*,' SO NAY NHO HON HOAC BANG 50' GOTO 40

30 PRINT*,' SO NAY LON HON 50' 40 CONTINUE

END

Các cấu trúc IF dạng 2, 3, IF số học câu lệnh kết thúc lệnh chu trình DO

Ví dụ 2.8 Giả sử ta cần liệt kê tất số nguyên chia hết cho 13 phạm vi từN1đến N2 với N1 N2được nhập từ bàn phím Khi chương trình viết sau sử dụng lệnh chu trình DO dạng dạng mà khơng thể sử dụng dạng 1:

Program Cach_1 ! Dung Chu trinh DO dang 2

write(*,'(A\)')' Cho hai so nguyen N1 va N2: ' read*, N1, N2

if (N1 > N2 OR N2 < 13) then Print*, ' So lieu khong hop le &

& hoac khong co so nao chia het cho 13' Stop

end if

(54)

if (mod(i,13)==0) then print*, i

end if 10 Continue End

Hoặc

Program Cach_2 ! Dung Chu trinh DO dang 3

write(*,'(A\)')' Cho hai so nguyen N1 va N2: ' read*, N1, N2

if (N1 > N2 OR N2 < 13) then Print*, ' So lieu khong hop le &

& hoac khong co so nao chia het cho 13' Stop

end if Do i=N1,N2

if (mod(i,13)==0) then print*, i

end if enddo End

2.3 KẾT HỢP DO VÀ IF

Như thấy ví dụ 2.8, chu trình DO bao hàm cấu trúc rẽ nhánh IF ngược lại Nghĩa chu trình DO có thể kiểm sốt toàn cấu trúc IF, cấu trúc IF có chứa trọn vẹn chu trình DO Nhất thiết chúng không phép giao Cú pháp tổng quát cấu trúc sau

Dạng 1: Cấu trúc IF nằm chu trình DO: DO bdk = TriDau, TriCuoi, Buoc

IF (BThuc_Logic) THEN

END IF END DO

Dạng 2: Chu trình DO nằm cấu trúc IF: IF (BThuc_Logic) THEN

DO bdk = TriDau, TriCuoi, Buoc

END DO END IF

(55)

PROGRAM IFinDO ! C.trúc IF nằm C.trình DO Do i=1,10000

If (mod(i,2)==0) write(*,*) i If (i == 20) then

print*,' Ket thuc sau lan lap thu ',i stop

End If Enddo END

Ví dụ 2.10 Đọc vào hai số nguyên M N Nếu MN in số từMđến N, ngược lại in thơng báo M > N

PROGRAM DOinIF ! C.trình DO nằm C.trúc IF Print*,' Cho hai so nguyen: '

Read*, M, N if (M <= N) then

write(*,*)' Lap tu ',M, ' den ',N Do i=M,N

write(*,*) i Enddo Else

write(*,*)' M > N' End If

END

2.4 RẼ NHÁNH VỚI CẤU TRÚC SELECT CASE

Một phương pháp hữu hiệu để chuyển điều khiển chương trình sử dụng cấu trúc rẽ nhánh SELECT CASE. Dạng tổng quát cấu trúc sau

SELECT CASE (BThuc_Chon) CASE (Chon1)

Các_câu_lệnh_1 CASE (Chon2) Các_câu_lệnh_2

CASE DEFAULT Các_câu_lệnh_n END SELECT

Trong BThuc_Chon, Chon1, Chon2,… phải có kiểu liệu số nguyên, lôgic CHARACTER*1 BThuc_Chon biểu thức tính tốn, cịn gọi số chọn Chon1, Chon2,… giá trị khoảng giá trị có BThuc_Chon Nếu có nhiều giá trị rời rạc, chúng phải liệt kê cách dấu phẩy; khoảng giá trị liên tiếp, chúng phải biểu diễn hai giá trịđầu cuối khoảng, phân cách dấu hai chấm (:) Các_câu_lnh_1, Các_câu_lnh_2,… tập câu lệnh thực Nếu biểu diễn sơđồ khối cấu trúc gần giống với hình 2.4, BThuc_Logic_1,… thay mệnh đề BThuc_Chon thuộc tập Chon1,…

(56)

Bắt đầu: Xác định giá trị (Bieu_Thuc_Chon)

Nếu giá trị Bieu_Thuc_Chon thuộc tập (Chon1) Thực Các_câu_lnh_1

Nếu giá trị Bieu_Thuc_Chon thuộc tập (Chon2) Thực Các_câu_lnh_2

Nếu Bieu_Thuc_Chon nhận giá trị khác Thực Các_câu_lnh_n

Kết thúc

Ví dụ 2.11 Viết chương trình xem số ngày tháng năm INTEGER Month, Year

Print'(A\)',' Xem so cua thang nao?' Read*, Month

SELECT CASE (Month)

CASE (1,3,5,7,8,10,12) ! Các tháng có 31 ngày Print*,' Thang ', Month,' co 31 ngay' CASE (4,6,9,11) ! Các tháng có 30 ngày

Print*,' Thang ', Month,' co 30 ngay' CASE (2) ! Có 28 29 ngày

Print'(A\)',' Nam nao?'

Read*, Year

IF (Mod(Year,4).EQ.0.AND & & Mod(Year,100).NE.0.OR &

& Mod(Year,400).EQ.0) then ! Năm nhuận Print*,' Thang ', Month,' Nam ',& Year, ' co 29 ngay'

Else ! Năm bình thường

Print*,' Thang ', Month,' Nam ',& Year, ' co 28 ngay'

End IF

CASE DEFAULT

Print*,' Khong co thang ', Month END SELECT

END

Trong ví dụ 2.11, giá trị Bieu_Thuc_Chon được xác định lệnh READ*, Month, tức Monthlà Bieu_Thuc_Chon.Vì Chon1, Chon2nhận tập giá trị rời rạc (các tháng không liên tục) nên chúng liệt kê cách dấu phẩy

Ví dụ 2.12 Gõ một ký tự cho biết chữ hay chữ số CHARACTER*1 char

Print*,' Hay go mot ky tu:' Read*, Char

(57)

CASE ('0':'9')

WRITE (*, *) "Day la chu so ", Char CASE ('A':'Z','a':'z')

WRITE (*, *) "Day la chu cai ",Char CASE DEFAULT

WRITE (*, *) "Day khong phai chu so, & &cung khong phai chu cai."

WRITE (*, *) "Day la ky tu ", Char END SELECT

END

Ở đây, tập giá trị Chon1, Chon2 những dãy giá trị liên tục khoảng nên chúng liệt kê cách nối giá trịđầu khoảng cuối khoảng dấu hai chấm (:)

2.5 THAO TÁC VỚI HẰNG VÀ BIẾN KÝ TỰ (CHARACTER)

Ở mục 1.4.2 ta xét kiểu liệu ký tự cách khai báo biến, có kiểu ký tự Hằng ký tự tập hợp ký tự thuộc bảng mã ASCII, không bao gồm ký tựđiều khiển, lập thành dãy

đặt cặp dấu nháy đơn (‘ ’) dấu nháy kép (“ ”) Biến ký tự biến có kiểu ký tự, khai báo lệnh CHARACTER Các biến ký tự có thểđược gộp với để tạo thành xâu ký tự

Ví dụ 2.13 Trong chương trình làm quen ví dụ 1.1 ta gặp cách thao tác với biến ký tự chưa phân tích chúng Ta trở lại với ví dụ Chương trình sau đưa lời chào mừng ta gõ tên vào hỏi

Program WelCome CHARACTER *20 Name Print *,'Ten ban la gi ?' Read*, Name

Write(*,*) 'Xin chao ban ', Name END

Trong chương trình này, lệnh PRINT in ký tự (Ten ban la gi ?), lệnh READ*đọc giá trị biến ký tự Name ta nhập vào, lệnh WRITE in ký tự (Xin chao ban ) giá trị biến ký tự Name Biến Name khai báo có kiểu ký tự với độ dài cực đại 20 Khi chạy chương trình này, ta nhập xâu có chứa dấu cách (ví dụ Hoang Nam) mà khơng đặt cặp dấu nháy, giá trị biến Name bị cắt bỏ phần bên phải kể

từ vị trí dấu cách Chẳng hạn chạy lại chương trình: Ten ban la gi ?

Hoang Nam

Xin chao ban Hoang

(chứ Hoang Nam ta mong muốn) Nhưng ta gõ vào “Hoang Nam” (đặt cặp dấu nháy) kết nhận lại hồn tồn bình thường Nếu thay câu lệnh

Read*, Name câu lệnh

(58)

thì giá trị biến Name nhập vào không đặt dấu nháy, trường hợp dấu nháy sẽđược hiểu phận Name Ví dụ, giả sử ta thay câu lệnh READ* chạy lại chương trình:

Ten ban la gi ?

Hoang Nam

Xin chao ban Hoang Nam

nhưng

Ten ban la gi ?

‘Hoang Nam’

Xin chao ban ‘Hoang Nam’

Nếu độ dài xâu ký tự vượt độ dài khai báo cực đại biến ký tự phần bên phải xâu bị cắt bỏ Ví dụ:

CHARACTER *7 Name Name = ‘Hoang Nam’

Kết biến Name có giá trị ‘Hoang N’, độ dài cực đại Name (ký tự), không

đủđể chứa nội dung giá trị‘Hoang Nam’.

Ví dụ 2.14 Chương trình sau ví dụ sử dụng phép toán gộp xâu ký tự Character Ho*7,Dem*7, Ten*7, HoTen*21

Ho=‘Nguyen’ Dem=‘Van’ Ten=‘Thanh’

HoTen=Ho//Dem//Ten

PRINT*,’123456712345671234567’ PRINT*, HoTen

END

Khi chạy chương trình ta nhận được: 123456712345671234567

Nguyen Van Thanh

Dòng kết viết dãy chữ số nhằm mục đích để ta đối sánh độ dài xâu cách dễ dàng Biến HoTen có giá trị giá trị ba biến Ho, Dem Ten Vì ba biến

đều có độ dài khai báo (ký tự), nên Van Thanhcó khoảng trống (4 dấu cách) BÀI TẬP CHƯƠNG

2.1 Viết chương trình hiển thị số nguyên khoảng từ 10 đến 20 bậc hai tương

ứng chúng

2.2 Viết chương trình tính tổng số ngun liên tiếp khoảng từ 101 đến 1000 hiển thị kết lên hình dạng:

(59)

2.3 Viết chương trình tính tổng số nguyên chẵn liên tiếp khoảng từ đến 1000 hiển thị kết lên hình dạng:

TONG CAC SO CHAN TU DEN 1000 LA: XXXXXX

2.3 Kết điểm thi 10 môn học sinh viên ghi file DIEM.TXT Viết chương trình đọc điểm thi mơn, tính điểm trung bình mơn hiển thị lên hình

điểm mơn điểm trung bình sinh viên

2.4 Kết quảđiểm thi 10 mơn học sinh viên ghi file DIEM.TXT Kết thi

được xem đạt yêu cầu điểm thi lớn Viết chương trình đọc điểm thi mơn cho biết số mơn thi đạt u cầu sinh viên

2.5 Viết chương trình nhập vào toạđộ ba điểm A(x1,y1), B(x2,y2), C(x3,y3) Nếu ba điểm không

thẳng hàng tính diện tích tam giác ABC, ngược lại đưa thông báo "Ba diem A, B, C thang hang"

2.6 Viết chương trình nhập vào toạ độ ba điểm A(x1,y1), B(x2,y2), C(x3,y3) Nếu ba điểm không

thẳng hàng xác định toạđộ trọng tâm tam giác ABC, ngược lại đưa thơng báo "Ba diem A, B, C thang hang"

2.7 Viết chương trình nhập vào toạ độ ba điểm A(x1,y1), B(x2,y2), C(x3,y3) Nếu ba điểm khơng

thẳng hàng tính độ dài đường trung tuyến tam giác ABC, ngược lại đưa thơng báo "Ba diem A, B, C thang hang"

2.8 Viết chương trình nhập vào số thực a, b, c thoả mãn điều kiện ba cạnh tam giác tính diện tích, đường cao bán kính đường trịn ngoại tiếp tam giác Gợi ý: Bán kính

đường trịn ngoại tiếp R=(abc)/(4S), với S diện tích

2.9 Viết chương trình nhập vào hệ số a, b và: 1) Giải phương trình ax + b = 0; 2) Giải bất phương trình ax + b >

2.10 Viết chương trình nhập vào hệ số a1, b1, c1, a2, b2, c2 giải hệ phương trình: ⎩

⎨ ⎧

= +

= +

2 2

1 1

c y b x a

c y b x a

2.11 Viết chương trình nhập vào số thực a, b, c giải bất phương trình ax2 + bx + c >

2.12 Tìm số nguyên dương n lớn thoả mãn điều kiện: a) 3n3− 212n<10; b) 123n1/2− 3n + ≤ 54; en− 1999lgn <

2.13 Viết chương trình nhập vào n số thực cho biết có số dương, âm 2.14 Điểm thi học kỳ lớp sinh viên cho file DIEM_HK.TXT Cấu trúc file

(60)

tiếp theo tương ứng điểm thi M mơn học (điểm thi có giá trị khoảng 0−10) Viết chương trình đọc số liệu file tính điểm trung bình chung học tập sinh viên theo cơng thức:

Điểm trung bình chung = ( ) ( )

( )

∑ ∑

= =

n i n i

x

1

i m«n trinh häc Sè

i môn trinh học Số i môn iểm Đ

In kết lên hình thành hai cột, tương ứng mã số sinh viên điểm trung bình chung học tập sinh viên

2.15 Phát triển tập 2.14 cách, tiến hành xếp loại học tập cho sinh viên dựa vào điểm trung bình chung học tập (TBCHT) sau:

− Nếu TBCHT < 5.0: Loại yếu (YEU)

− Nếu 5.0 ≤ TBCHT < 7.0: Loại trung bình (TRUNG BINH)

− Nếu 7.0 ≤ TBCHT < 8.5: Loại (KHA)

− Nếu 8.5 ≤ TBCHT < 9.0: Loại giỏi (GIOI)

− Nếu TBCHT ≥ 9.0: Loại xuất sắc (XUAT SAC)

In kết lên hình thành ba cột: cột mã số sinh viên, cột điểm trung bình chung học tập, cột kết xếp loại

2.16 Viết chương trình nhập vào số lượng mơn học (M), số học trình mơn, họ tên

điểm thi M mơn học N sinh viên tính điểm trung bình chung học tập, xếp loại học tập theo cách thức tính xếp loại tập 2.14 2.15 In kết vào file KETQUA.TXT dạng:

HO VA TEN DIEM TBCHT XEP LOAI Nguyen Van A 8.7 Xuat sac

(61)

CHƯƠNG CÁC CẤU TRÚC MỞ RỘNG 3.1 CHU TRÌNH DO TỔNG QUÁT VÀ CHU TRÌNH DO LỒNG NHAU

Trong chương ta xét dạng chu trình DO, dạng dạng địi hỏi phải sử dụng dịng lệnh có nhãn để kết thúc chu trình Điều làm cho ta nhiều lúc phải nhớ cách máy móc hệ thống nhãn này, chương trình có nhiều vịng lặp vịng lặp địi hỏi phải kiểm sốt đoạn chương trình dài Cịn cấu trúc dạng 3, chương trình có chứa nhiều vịng lặp lồng làm cho ta lúng túng cần phân biệt vòng lặp bắt đầu kết thúc ởđâu Sự bất tiện tăng lên chương trình có lỗi ta phải gỡ rối Để khắc phục nhược

điểm này, Fortran 90 cho phép sử dụng chu trình DO tổng quát, vịng lặp gán tên, tương tự nhãn, tên đặt gắn với lệnh chu trình nên giúp ta dễ nhớ dễ

kiểm sốt Cú pháp câu lệnh chu trình tổng quát sau Ten_ChuTrinh: DO bdk = TriDau, TrCuoi [, Buoc] Các_câu_lệnh

END DO Ten_ChuTrinh

Về nguyên tắc, tác động chu trình DO hồn tồn giống với chu trình DO trước Ngồi ra, tất dạng chu trình DOđều lồng cho chu trình ngồi kiểm sốt tồn chu trình Có thể có cấu trúc lồng sau

Dạng 1: DO m1 bdk1=

DO m2 bdk2= Các_câu_lệnh m2 Câu_lệnh_kết_thúc [ hoặc: m2 CONTINUE ]

m1 Câu_lệnh_kết_thúc [ hoặc: m1 CONTINUE ]

Dạng 2: DO bdk1=

(62)

Dạng 3:

ChuTrinh_1: DO bdk1=

ChuTrinh_2: DO bdk2= Các_câu_lệnh

END DO ChuTrinh_2

END DO ChuTrinh_1

Dang dạng dạng chu trình lồng sử dụng cấu trúc DOở chương Dạng chu trình lồng sử dụng cấu trúc DO tổng quát Trong cấu trúc trên, Các_câu_lnh cũng chu trình DO khác Nghĩa là, ngun tắc ta sử dụng cấu trúc có nhiều hai chu trình lồng

Ví dụ 3.1 Lập chương trình tính tổng điểm thi đại học cho thí sinh PROGRAM TinhDiem

WRITE(*,’(A\)’)” Cho so thi sinh can tinh:” Read*, N

ThiSinh: DO i=1,N

TongDiem=0.0

MonThi: DO j=1,3

Print*, “Cho diem thi mon “, J,& &” cua TS thu “, I

Read*,Diem

TongDiem=TongDiem+Diem END DO MonThi

Write(*,’(” Diem TS “,I3,”=”,F5.1)’)& I,TongDiem END DO ThiSinh

END

Trong chương trình ta sử dụng hai chu trình lồng dạng tổng qt, chu trình ngồi đặt tên ThiSinh, lặp theo số thí sinh cần phải tính, cịn chu trình

đặt tên MonThi, hàm ý lặp theo số lượng môn thi Cách đặt tên mang tính gợi nhớ 3.2 CẤU TRÚC IF TỔNG QUÁT VÀ CẤU TRÚC IF LỒNG NHAU

Tương tự cấu trúc chu trình DOđã nói mục 3.1, để giảm bớt “sức ép” phải nhớ máy móc lúc lập trình, Fortran 90 đưa vào tên cấu trúc rẽ nhánh IF gọi cấu trúc IF tổng quát Cú pháp sau

Ten_Cau_Truc: IF (BThuc_Logic) THEN

END IF Ten_Cau_Truc

Hoặc

Ten_Cau_Truc: IF (BThuc_Logic) THEN

ELSE Ten_Cau_Truc

(63)

Hoặc

Ten_Cau_Truc: IF (BThuc_Logic_1) THEN

ELSE IF (BThuc_Logic_2) THEN .…

ELSE IF (BThuc_Logic_3) THEN

ELSE Ten_Cau_Truc

END IF Ten_Cau_Truc

Nói chung khơng có khác biệt chức cấu trúc IF tổng quát cấu trúc IF thông thường xét chương 2, ngoại trừ thêm Ten_Cau_Truc để “đánh dấu” xác định vị trí khối cấu trúc

Cấu trúc IF lồng cho cấu trúc nằm trọn vẹn cấu trúc IF (BThuc_Logic_1) THEN

IF (BThuc_Logic_2) THEN

END IF END IF

Hoặc

Ngoai: IF (BThucLogic_1) THEN

Trong: IF (BThuc_Logic_2) THEN

END IF Trong

END IF Ngoai

Trong Trong Ngoai tương ứng tên cấu trúc IF

Ví dụ 3.2 Để minh họa cho cách sử dụng cấu trúc IF lồng nhau, sau sẽđưa phương án viết chương trình giải phương trình ax2 + bx + c = với cấu trúc IF tổng quát

Ta thấy, biểu thức tổng quát phương trình đa thức có bậc cao Tuy nhiên, phụ thuộc vào giá trị hệ số a, b, c mà phương trình có bậc 2, Do

đó, để giải toán trước hết ta lập dàn thực hiện, gồm bước sau Bước 1: Nhập hệ số a, b, c

Bước 2: Nếu a=0: (giải phương trình bậc bx + c = 0) – Nếu b=0: (bậc phương trình 0)

(64)

– Nếu b≠0: Trả lời: Nghiệm x=−c/b

Bước 3: Nếu a≠0: (giải phương trình bậc hai ax2 + bx + c = 0)

– Tính DelTa=b*b−4*a*c

– Nếu DelTa<0: Trả lời: Vơ nghiệm (hoặc nghiệm ảo) – Nếu DelTa≥0:

+ Tính nghiệm

+ Trả lời: Nghiệm x1, x2 =(−b±(DelTa)0.5)/(2a)

Bước 4: Kết thúc

Dựa dàn ta có mã chương trình sau: PROGRAM GiaiPTb2

REAL a, b, c, DelTa, x1, x2 Print*,’ Cho cac he so a,b,c:’ Read*, a,b,c

XetA: IF (a==0) THEN

XetB: IF (b==0) THEN

XetC: IF (c==0) THEN

Print*,’ Phuong Trinh co VO SO NGHIEM’ ELSE XetC

Print*,’ Phuong Trinh VO NGHIEM’ END IF XetC

ELSE XetB

Print*, ‘Ph.trinh co nghiem x=‘, -c/b END IF XetB

ELSE XetA

DelTa=b*b-4*a*c

XetDelTa: IF (DelTa<0) THEN

Print*,’Phuong trinh KHONG CO NGHIEM THUC’ ELSE XetDelTA

DelTa=SQRT(DelTa) X1=( -b - DelTa) / (2*a) X2=( -b + DelTa) / (2*a)

Print*,’PT co cac nghiem X1=‘,X1, & ’ X2=‘, X2

END IF XetDelTa

END IF XetA

END

Qua nhận thấy rằng, cấu trúc IF lồng nhiều cấp Hơn nữa, sử

(65)

3.3 CHU TRÌNH NGẦM

Trước hết ta xét hai ví dụ sau, chúng thực việc in lên hình số

ngun

Ví dụ 3.3.1: In số năm dòng khác DO I = 1,

PRINT*, I END DO END

Nếu chạy chương trình bạn nhận kết hình là: 1

2 3 4 5

Ví dụ 3.3.2: In số dòng PRINT*, (I, I = 1, 5)

END

Trong trường hợp bạn nhận kết là:

Lệnh PRINT* ví dụ 3.3.2 cho phép in giá trị I, với I tăng dần từ đến Khác với ví dụ 3.3.1, lệnh PRINT* thực lần, lần in ghi, nên kết nhận

được số in dịng, ví dụ 3.3.2 lệnh PRINT* chỉđược thực lần, tức

in ghi, nên giá trịđều nằm dòng Người ta gọi vòng lặp in giá trị I lệnh PRINT* ví dụ 3.3.2 chu trình DO ngầm Loại chu trình DO sử dụng nhiều, việc kết xuất liệu đọc liệu từ file TEXT Ví dụ, chương trình sau cho phép in 100 số nguyên dương theo thứ tự tăng dần 10 dòng, dòng 10 số

PROGRAM BangSoNguyen DO I=1,91,10

PRINT '(10I4)',(j,j=i,i+9) ENDDO

END

3.4 ĐỊNH DẠNG DỮ LIỆU BẰNG LỆNH FORMAT

Trong chương trước ta gặp số trường hợp sử dụng lệnh định dạng FORMATđểđọc vào kết xuất liệu có qui cách Tuy nhiên vài ví dụđơn giản Trong mục ta sẽđề cập chi tiết câu lệnh Cú pháp câu lệnh sau

(66)

Trong m nhãn câu lệnh, Mô_t_định_dng những qui ước đểđọc/ghi liệu theo qui tắc định Fortran định nghĩa nhiều qui tắc định dạng, có định dạng áp dụng cho cảđọc ghi liệu, có định dạng áp dụng cho đọc ghi liệu Bảng 3.1 dẫn qui tắc định dạng sử dụng phổ biến nhất, cột mơ tả ký hiệu định dạng

xuất lệnh FORMAT, cột mô tả ý nghĩa sử dụng nhập kết xuất liệu, cột đưa số ví dụđơn giản viết qui tắc định dạng lệnh FORMAT Bạn đọc tìm hiểu kỹ

hơn qua tài liệu tham khảo tra cứu chức trợ giúp Fortran Ví dụ 3.4:

INTEGER N, M REAL X, Y, Z

PRINT 10, ' Cho hai so nguyen: '

10 FORMAT (A\) ! Viet xong, giu tro tren cung dong READ (*, *) N, M

WRITE (*, '(A\)')' Cho ba so thuc: ' READ (*, *) X, Y, Z

WRITE (*, 20) N, M, X, Y, Z

20 FORMAT (20X, 'Cac so vua nhap la : '/2x,& &' Cac so nguyen: ',' N=', I6,&

&' M=',I6/2x,' Cac so thuc: ',2x,& &' X=',F6.1,' Y=',F6.1,' Z=', F6.1) END

Bảng 3.1 Qui cách mô tảđịnh dạng FORMAT

Mô tả Ý nghĩa Ví dụ

Iw[.m] Đọc/in số nguyên I5, I5.5, 4I6 Bw[.m] Đọc/in số nhị phân B4 Ow[.m

]

Đọc/in số số O5 Zw[.m] Đọc/in số số 16 Z10.3

Fw.d Đọc/in số thực dấu phẩy tĩnh F10.3, F5.0, 5F7.2

Ew.d Đọc/in số thực dấu phẩy động E14.7, 5E10.6 Dw.d Đọc/in số thực độ xác gấp

đôi

D14.7, 5D10.6 A[w] Đọc/in biến ký tự A, A1, A20, 4A7

Lw Đọc/in biến lôgic L4, 3L5

nX Bỏ qua n ký tự 1X, 5X

Tc Chuyển trỏđến vị trí thứ c tính từ

vị trí ghi

T10 TLc Chuyển trỏ sang trái c ký tự tính

từ vị trí trỏ thời

TL10 TRc Chuyển trỏ sang phải c ký tự tính

từ vị trí trỏ thời

TR10

/ Xuống dòng 2x, 5F10.3/

2x,7F10.3 \

$

Giữ ghi A\

(67)

KTự nháy) duoi’

Ghi chú: w độ rộng trường, d số chữ số sau dấu chấm thập phân, m số

ký tự mà số nguyên chiếm, kể chữ số đứng trước, n số ký tự bỏ qua

Định dạng FORMAT có thểđược mơ tả câu lệnh READ WRITE PRINT mà không thiết sử dụng câu lệnh FORMAT Chẳng hạn, câu lệnh

WRITE (*, 30) X, Y, Z

30 FORMAT (3X, 2F10.3, E12.5) tương đương với câu lệnh

WRITE (*, ’(3X, 2F10.3, E12.5)’) X, Y, Z

Khi đọc liệu vào, ta dùng định dạng tự ví dụ trước đây, dùng định dạng có qui cách Ví dụ, trường hợp sau cho kết

Giả sử, muốn nhập vào ba sốx=12.3, y=23.45, z=123.4 Với câu lệnh READ (*, *) X, Y, Z

ta cần gõ vào:

12.3 23.45 123.4 (Các số cách dấu cách) Nhưng viết câu lệnh dạng:

READ (*,’(3F5.2)’) X, Y, Z ta gõ vào dãy số liên tục:

012300234512340

Vì định dạng mô tả ’(3F5.2)’ nên sốđược nhập vào nhóm gồm chữ số chữ số cuối nhóm chữ số sau dấu chấm thập phân Ta thay số khơng có nghĩa dấu cách

3.5 CHU TRÌNH LẶP KHƠNG XÁC ĐỊNH

Chu trình DOđã xét trước chu trình lặp với số bước lặp xác định tham số TriDau, TriCuoi Buoc. Trong thực tế ta thường gặp nhiều tốn số bước tính tốn cần lặp lặp lại xác định cách cụ thể, mà xác định thông qua

điều kiện cho trước Cấu trúc lặp gọi lặp không xác định 3.5.1 Cấu trúc kết hợp IF GOTO

Có thể tạo chu trình lặp khơng xác định việc kết hợp IF GOTO như sau m Câu_lnh_đầu_vòng_lp

Các_câu_lnh_tiếp_theo_trong_vòng_lp

IF (BThuc_Logic) GOTO m hoặc:

m Câu_lnh_đầu_vòng_lp

Các_câu_lnh_tiếp_theo_trong_vòng_lp

(68)

Các_câu_lnh_x_lý_trước_khi_lp_li

GOTO m END IF

Trong m nhãn câu lệnh trình cần lặp; BThuc_Logic điều kiện để lặp lại trình Nếu BThuc_Logic nhận giá trị .TRUE. chương trình

chuyển điều khiển đến câu lệnh đầu vòng lặp, ngược lại, BThuc_Logic nhận giá trị.FALSE. trình lặp kết thúc Sơ đồ khối mơ tả tác động chu trình cho hình 3.1

Ví dụ 3.5 Viết chương trình nhập vào số dương khơng vượt q 10

Với yêu cầu này, chương trình phải bảo đảm điều kiện, chừng số nhập vào số dương khơng vượt q 10 phải nhập lại Như vậy, điều kiện quay lại vòng lặp ởđây số nhập vào số âm số 0, số lớn 10; nội dung cần lặp nhập vào số Ta có qui trình sau

1) Nhập vào số X 2) Kiểm tra số X:

− Nếu X≤0 X>10 + Thơng báo lỗi + Quay lại bước 1) 3) Kết thúc

Chương trình có thểđược viết: PROGRAM IF_GOTO

REAL X

10 PRINT ‘(A\)’,' CHO MOT SO: ' READ*, X

IF (X <= 0.OR.X > 10) THEN PRINT*,' SO VUA NHAP=',X PRINT*,' SAI ! NHAP LAI !' PRINT*

GOTO 10 END IF PRINT*

PRINT*,' DUNG ROI! SO VUA NHAP=',X END

(69)

3.5.2 Cấu trúc DO EXIT

Chu trình lặp khơng xác định có thểđược cấu tạo kết hợp DO EXIT Cú pháp cấu trúc sau

Dạng 1: [TenChuTrinh:] DO IF (BThuc_Logic) EXIT

Các_câu_lnh

END DO [TenChuTrinh] Dạng 2:

[TenChuTrinh:] DO Các_câu_lnh

IF (BThuc_Logic) EXIT END DO [TenChuTrinh]

Sơđồ khối mô tả tác động cấu trúc cho hình 3.2 Ta cần ý khác nhau giữa hai cấu trúc Đối với cấu trúc dạng 1, BThuc_Logic xác định trước Các_câu_lnh được thực hiện, nên Các_câu_lnh sẽ khơng thực lần từđầu BThuc_Logic nhận giá trị TRUE Trong đó, cấu trúc dạng 2, Các_câu_lnh được thực lần

Dạng Dạng

Hình 3.2 Cấu trúc lặp DO EXIT

Ví dụ 3.6: Hãy làm lại ví dụ 3.5 sử dụng cấu trúc DO EXIT. Với cấu trúc dạng ta có chương trình:

PROGRAM LAP_1 REAL X

X = 999 ! Khoi tao X

CauTruc1: DO

IF (X > 0.AND.X <= 10) EXIT PRINT '(A\)','CHO MOT SO: ' READ*, X

(70)

END IF

END DO CauTruc1

PRINT*

PRINT*,' DUNG ROI! X =',X END

Trong trường hợp này, câu lệnh X = 999

có tác dụng khởi tạo giá trị X Nó câu lệnh bắt buộc để tránh việc tham chiếu đến biến chưa xác

định câu lệnh

IF (X > 0.AND.X <= 10) EXIT Bây ta thay câu lệnh

X = 999

bởi câu lệnh khác X thỏa mãn điều kiện < X≤ 10, chẳng hạn X =

và chạy lại chương trình Kết nhận thật bất ngờ! Bạn đọc giải thích Với cấu trúc dạng ta viết chương trình sau:

REAL X

CauTruc2: DO

PRINT '(A\)','CHO MOT SO: ' READ*, X

IF (X > 0.AND.X <= 10) EXIT PRINT*,' SO VUA NHAP=',X PRINT*,' SAI ! NHAP LAI !' PRINT*

END DO CauTruc2

PRINT*

PRINT*,' DUNG ROI! X =',X END

Trong cấu trúc ta không cần khởi tạo giá trị X Bạn đọc giải thích sao? 3.5.3 Cấu trúc DO WHILE…END DO

Cú pháp cấu trúc có dạng: DO WHILE (BThuc_Logic)

Các_câu_lnh

END DO

Tác động cấu trúc hoàn toàn tương đương với cấu trúc [TenChuTrinh:] DO

IF (BThuc_Logic) EXIT Các_câu_lnh

END DO [TenChuTrinh]

(71)

REAL X

PRINT '(A\)',' CHO MOT SO: ' READ*, X

DO WHILE (X <= 0.OR.X > 10) ! Điều kiện lặp lại PRINT*,' SAI ! '

PRINT*

PRINT '(A\)',' CHO MOT SO: ' READ*, X ! X nhận giá trị END DO

PRINT*

PRINT*,' DUNG ROI! SO VUA NHAP=',X END

Hai dòng lệnh thứ hai thứ ba chương trình thay câu lệnh gán giá trị khởi tạo Nếu từđầu giá trị X thỏa mãn điều kiện < X ≤ 10 Các_câu_lnh nằm DO WHILE END DO không bao giờđược thực

3.5.4 Lệnh CYCLE

Trong số trường hợp thực chu trình lặp, tùy theo điều kiện, cần phải bỏ qua số

bước đó, chưa khỏi hồn tồn chu trình, ta sử dụng câu lệnh CYCLE Cú pháp câu lệnh sau:

CYCLE [Tên_Chu_Trình]

Lệnh CYCLE nằm chu trình lặp DO DO WHILE, có tác dụng bỏ qua câu lệnh vịng lặp nằm sau CYCLE chuyển điều khiển khối kiểm tra điều kiện lặp lại chu trình có tên Tên_Chu_Trình

Lệnh CYCLE nằm chu trình lồng Nếu khơng Tên_Chu_Trình CYCLE có tác động chu trình lặp chứa

Ví dụ, ta xét chương trình sau INTEGER I

INTEGER, PARAMETER :: N = 10

LapDO: DO I=1,N

print*,'Chi so vong lap DO: ',i IF (i>3) CYCLE LapDO

print*,'Lan duoc LAP boi DO:',i END DO LapDO

END

(72)

Trên thực tế kết hợp CYCLE EXIT chu trình lặp phức tạp Ta

khảo sát kỹ ví dụ sau để hiểu rõ tác động câu lệnh khác chúng INTEGER i,j,k

INTEGER, PARAMETER :: N = 10

write(*,'(/A, I2)')' Dieu khien lap su dung & & CYCLE va EXIT, N = ', N

write (*,900)

Vong1: DO i = 1, n if (i > 3) EXIT Vong1

write (*,910) i Vong2: DO j = 1, n if (j > 2) CYCLE Vong2

if (i == 2.and.j > 1) EXIT Vong2

write (*,920) j Vong3: DO k = 1, n if (k > 2) CYCLE Vong3

if (i == 1.and.j > 1) EXIT Vong2

write (*,930) k END DO Vong3

END DO Vong2

END DO Vong1

WRITE (*,'(/A)') ' Hoan tat cac chu trinh.' 900 FORMAT(/' Vong: ') 910 FORMAT(11x, i2)

920 FORMAT(21x, i2) 930 FORMAT(31x, i2) END

Khi chạy chương trình này, kết nhận hình có dạng sau: Dieu khien lap su dung CYCLE va EXIT, N = 10

Vong:

Hoan tat cac chu trinh

(73)

chu trình DO thứ hai thứ ba sau thực Cịn I>3 khỏi chu trình Vong1 với giá trị I=4 Nhưng ta thay câu lệnh

if (i > 3) EXIT Vong1 câu lệnh

if (i > 3) CYCLE Vong1

thì kết nhận hoàn toàn tương tự, giá trị biến I sau thoát khỏi chu trình 10 (bằng N) Sở dĩ khác EXIT CYCLE Trong câu lệnh EXIT tạo tác động làm kết thúc chu trình cách cưỡng bức, lệnh CYCLE bỏ qua việc thực câu lệnh sau nó, cịn chu trình thực kết thúc bình thường Trong chu trình DO có nhãn Vong2, câu lệnh

if (j > 2) CYCLE Vong2

có tác dụng bỏ qua câu lệnh sau (nhưng tiếp tục thực vịng lặp) J > 2, câu lệnh

if (i == 2.and.j > 1) EXIT Vong2

lại có tác dụng làm kết thúc chu trình biểu thức (i==2.and.j>1) thỏa mãn Một cách tương tự, bạn đọc có thểđối chiếu kết tính chương trình với câu lệnh tương ứng để hiểu rõ thêm

3.5.5 Một số ví dụ chu trình lặp khơng xác định a Tính số PI theo công thức π= − + − +

7 1

Đây tổng chuỗi đan dấu mà số hạng tổng quát

1

− −

n ) ( n

, n=1,2,… Vậy ta có bước tính sau

1) Khởi tạo N=1, Tmp=0, EP=0.0001 [,SS=1.0] , DAU=1 2) Tính Sn = Tmp + DAU / (2*N − 1) (Số hạng thứ n)

(Tổng tích lũy đến số hạng thứ n) 3) Gán DAU = −DAU (đảo dấu)

4) Tính sai số tương đối SS = ABS((Sn−Tmp)/Sn) 5) So sánh SS với EP:

• Nếu SS >= EP:

• Lưu giá trị Sn vào Tmp • Quay lại bước 2)

• Nếu SS < EP:

(74)

• In kết Kết thúc chương trình

Sau lời chương trình viết cách khác sử dụng cấu trúc lặp trình bày mục trước Cũng cần lưu ý rằng, chương trình ởđây nhằm mục đích giải thích

khía cạnh lập trình mà chưa ý đến tính tối ưu chương trình Sau làm chủđược ngơn ngữ

lập trình, bạn đọc thay đổi viết lại cho tốt Cách 1: Sử dụng chu trình lặp kết hợp IF GOTO PROGRAM TINHPI1 ! Cach 1: IF & GOTO

REAL EPS, SS, PI, TMP INTEGER :: N, DAU = EPS=0.0001

TMP=0.0 N=1

100 PI=TMP+DAU/FLOAT(2*N-1) DAU = DAU

SS=ABS((PI-TMP)/PI)

PRINT*,'Vong lap thu ',N,' Sai so=',SS IF (SS >= EPS) THEN

TMP = PI N=N+1 GOTO 100 ELSE PI=PI*4.0 WRITE(*,300)PI

300 FORMAT(4X,' PI = ',F10.4) END IF

END

Cách 2: Sử dụng chu trình lặp kết hợp DO EXIT PROGRAM TINHPI2 ! CACH 2: DO & EXIT

REAL EPS, SS, PI, TMP INTEGER :: N, DAU = EPS=0.0001

TMP=0.0 N=1 DO

PI=TMP+DAU/FLOAT(2*N-1) DAU = DAU

SS=ABS((PI-TMP)/PI)

PRINT*,'Vong lap thu ',N,' Sai so=',SS IF (SS < EPS) EXIT

TMP = PI N=N+1 END DO PI=PI*4.0 WRITE(*,300)PI

(75)

END

Cách 3: Sử dụng cấu trúc DO WHILE PROGRAM TINHPI3 ! CACH 3: DO WHILE REAL EPS, SS, PI, TMP

INTEGER :: N, DAU = EPS=0.0001

TMP=0.0 N=1 SS=1.0

DO WHILE (SS >= EPS)

PI=TMP+DAU/FLOAT(2*N-1) DAU = DAU

SS=ABS((PI-TMP)/PI)

PRINT*,'Vong lap thu ',N,' Sai so=',SS TMP = PI

N=N+1 END DO PI=PI*4.0 WRITE(*,300)PI

300 FORMAT(4X,' PI = ',F10.4) END

b Tìm số nguyên dương lớn n thỏa mãn điều kiện 3n3−212n<10

INTEGER N, A N=0

A=999

DO WHILE (A < 10) N = N +

A = 3*N**3 - 212*N

PRINT*,'N = ',N,' A=', A END DO

PRINT*,'So phai tim la N = ', N1 END

Trong ví dụ ta cần ý đến cách khởi tạo giá trị biến N A BÀI TẬP CHƯƠNG

3.1 Viết chương trình tính sốπ theo công thức:

9 1 7 1 5 1 3 1 1

4 = − + − + −

π

với độ xác ε=10-4

3.2 Viết chương trình tính sốπ theo cơng thức:

11 9

1 7 5

1 3 1

1

8 = × + × + × + π

(76)

3.3 Viết chương trình nhập vào số thực a, b (a<b) tính tích phân: I = ∫ − π

b a

x

dx e

2

1

theo phương pháp hình thang với độ xác ε = 10-4

3.4 Viết chương trình nhập vào số thực a, b (a<b) tính tích phân: I = ∫b

a

2sinxdx

x theo

phương pháp hình thang với độ xác ε = 10-4

3.5 Thông tin bão cho file TRACK.TXT mà nội dung sau:

Date: 14-22 JUL 2003 Typhoon #8

(77)

34 19.70 103.80 07/22/18Z 35 997 TS

Trong đó, dịng ngày bắt đầu ngày kết thúc bão; dòng thứ hai số thứ tự

trong năm bão; dòng thứ ba tiêu đề cột dòng mà ý nghĩa chúng là: cột số thứ tự, cột cột vĩđộ kinh độđịa lý tâm bão; cột ghi tháng, ngày, vị trí tâm bão (mm/dd/hhz), với z ký hiệu lấy chuẩn quốc tế; cột tốc độ gió cực đại (knots); cột áp suất khí tâm bão (mb); cột cường độ bão, với ký hiệu TD − áp thấp nhiệt đới, TS − bão, TY−1, TY−2, −bão mạnh mức độ 1, 2, Viết chương trình đọc số liệu từ file, xử lý, tính tốn hiển thị lên hình thơng tin sau:

− Số ngày kéo dài bão (số ngày bão hoạt động)

− Thời điểm bão có tốc độ gió cực đại lớn

− Những khoảng thời gian bão đạt cường độ TD, TS TY

3.6 Phương pháp Archimedes để tính số p có thểđược mơ tả sơđồ thuật tốn sau: 1) Gán A = 1, N = SS=1.0E−6 (sai số cho phép)

2) Tiến hành:

− Thay N 2N

− Thay A 2− (4−A2)

− Gán L = NA/2

− Gán U = L/ 1−A2/2

− Gán PI = (U+L)/2 (là giá trịước lượng số p)

− Gán E = (U−L)/2 (là ước lượng sai số)

− Nếu E>=SS: quay lại bước 2), ngược lại thì:

In kết (In giá trị PI) 3) Kết thúc

Dựa vào thuật toán viết chương trình tính số p so sánh kết với tập 3.1 3.2

3.7 Viết chương trình tính in bảng giá trị đối số x hàm ⎥⎦

⎤ ⎢⎣

⎡ +

=

2 ) 20 1 ( sin )

(x x x

f π tương ứng cho x biến thiên khoảng đóng [−1; 1] với bước nhảy

(78)

3.8 Giả sử “sóng vng” với chu kỳ T có thểđịnh nghĩa hàm ⎩ ⎨ ⎧ < < − − < < = ) ( ) ( ) ( t T T t t f

Chuỗi Fourier hàm f(t) cho ∑∞

= ⎥⎦ ⎤ ⎢⎣ ⎡ + + ) ( sin k T t k k π

π Ta cần biết phải lấy hạng tử chuỗi để xấp xỉ tốt hàm f(t) Cho T = 1, viết chương trình tính hiển thị tổng n số hạng chuỗi cho t biến thiên khoảng từ 0−1 với bước nhảy 0.1 Chạy chương trình với giá trị n khác nhau, chẳng hạn n = 3, 6, 9,

3.9 Ký hiệu tổng N số tự nhiên S=1+2+ +N Viết chương trình xác định số N tổng S cho tổng S số lớn không vượt 1000

3.10 Sự tăng trưởng dân sốđược giảđịnh tuân theo qui luật mà số lượng dân số thời điểm t đó cho công thức:

0 0 ) ( ) ( x e x K Kx t x rt + − = −

trong x0 số lượng dân số thời điểm t=0, r tốc độ tăng trưởng K sốđặc trưng cho nhân tố mơi trường sống Viết chương trình tính in giá trị x(t) khoảng thời gian 200 năm với bước nhảy t bằng 10 Lấy x0 = 2, r = 0.1, K = 1000 Chạy chương trình với giá trị K khác so sánh kết quảđể nhận xét ý nghĩa K

3.11 Viết chương trình nhập vào dãy số thực với số lượng số chưa xác định Chương trình cho phép nhập gặp số nhập vào −999.0 kết thúc việc nhập Tính giá trị

trung bình số học dãy số thực In kết lên hình dạng: TRUNG BINH CUA N SO VUA NHAP = XXXXX.XX

trong N số lượng số tính trung bình (khơng kể số −999.0), giá trị trung bình in theo định dạng số thực dấu phẩy tĩnh với chữ số sau dấu chấm thập phân

3.12 Giả sử giá trị hợp lệ nhiệt độ không khí trạm quan trắc nằm phạm vi từ

−5 độđến 40 độ Viết chương trình nhập vào chuỗi số liệu quan trắc nhiệt độ không khí tính nhiệt

độ trung bình trạm Chương trình cho phép nhận giá trị số liệu hợp lệ với độ dài chuỗi số liệu In kết lên hình dạng:

DO DAI CHUOI = IIII, NHIET DO TRUNG BINH = XXXX.X

trong IIII số số nguyên dương chiếm độ rộng ký tự chỉđộ dài chuỗi quan trắc, nhiệt độ

trung bình in theo định dạng số thực dấu phẩy tĩnh với chữ số sau dấu chấm thập phân

(79)

CHƯƠNG CHƯƠNG TRÌNH CON (SUBROUTINE VÀ FUNCTION) VÀ MODUL

4.1 KHÁI NIỆM

Trong lập trình, tốn lớn, chương trình thường bao gồm nhiều

phận khác nhau, có phận thường sử dụng lặp lặp lại nhiều lần Ngoài ra, đoạn chương trình có thểđược sử dụng cho chương trình khác Việc viết chương trình có nhiều đoạn trùng lặp gây nhàm chán khơng hiệu quả, chí làm cho chương trình trở nên rối rắm Để tổ chức chương trình gọn gàng, dễ khai thác, Fortran cho phép phân mảnh chương trình tạo thành chương trình

Có hai khái niệm chương trình thủ tục (SUBROUTINE) hàm (FUNCTION) Các chương trình chia thành hai loại chương trình chương trình ngồi Ta chọn chương trình số chương trình để tạo thư viện riêng cho Tập hợp chương trình gọi modul Các chương trình (Main Program), chương trình ngồi (External Subprogram) modul gọi đơn vị chương trình (Program Unit) Về nguyên tắc, chương trình nằm đơn vị chương trình khác được biên dịch với đơn vị chương trình mà phụ thuộc, chương trình ngồi biên dịch cách độc lập Cái khác chương trình chương trình ngồi chỗ, chương trình sử dụng tên biến, khai báo đơn vị chương trình quản lý nó, chương trình ngồi, khơng phép nằm đơn vị chương trình khác nên khơng có tính chất

Cũng cần ý phân biệt khái niệm đơn vị chương trình, (bộ) chương trình file Trong file chứa nhiều đơn vị chương trình chúng gộp lại thành (bộ) chương trình Nói chung ta không nên tổ chức vậy, chương trình lớn, mà nên tách đơn vị chương trình ra, đơn vị chương trình chứa file Nói cách khác, (bộ) chương trình gồm chương trình n chương trình đơn vị chương trình chúng nên

được lưu trữ n+1 file tách biệt Cách tổ chức cho phép chương trình khác sử dụng chung đơn vị chương trình Tuy nhiên, ta khơng thể lưu trữ chương trình trong vào file tách biệt với đơn vị chương trình quản lý nó, ngoại trừ trường hợp sử dụng câu lệnh INCLUDE (sẽđược trình bày sau)

4.2 THƯ VIỆN CÁC HÀM TRONG

Trước đây, ta làm quen với cách sử dụng hàm thư viện Fortran Trong số ví dụ, hàm thư viện sử dụng, hàm tính bậc hai, hàm tính cosin góc,…

(80)

trong thư viện chương trình Fortran Sau ví dụ cách sử dụng hàm thư

viện

Ví dụ 4.1 Viết chương trình lập bảng tra giá trị hàm sin cosin góc nằm khoảng 0−90o

Ta viết chương trình sau PROGRAM BANG_SIN_COS

IMPLICIT NONE REAL Pi

INTEGER I,J PI=4.*atan(1.)

WRITE(*,'(" ",11I7)') (I,I=0,60,6) DO j=0,89

WRITE(*,'(I3,1X,11F7.5,I4)') &

J,(SIN((REAL(j)+I/60.)/180.*pi),I=0,60,6), 89-J ENDDO

WRITE(*,'(" ",11I7)') (60-I,I=0,60,6) END

Trong chương trình sử dụng ba hàm thư viện Fortran hàm ATAN, hàm SIN và hàm REAL Hàm ATAN(x)để tính acrtan số x Vì Fortran khơng định nghĩa số π nên ta phải tính π/4 = arctan (1), hàm SIN để tính sin góc từ 0−90o mà giá trị của chúng

khoảng lấy cách phút Đối số hàm lượng giác, sin, cos, tang, cotang, phải radian Còn hàm REAL dùng đểđổi số nguyên J thành số thực, khác với lệnh khai báo REAL dùng để khai báo biến có kiểu số thực phần khai báo

4.3 CÁC CHƯƠNG TRÌNH CON TRONG

4.3.1 Hàm (Internal FUNCTION) Hàm có thểđược khai báo sau [KiuDL][RECURSIVE] FUNCTION TenHam & ([Các_đối_s]) [RESULT (TenKetQua) ] [Các_câu_lnh_khai_báo]

[Các_câu_lnh_thc hin] [TenHam = ]

END FUNCTION [TenHam] Trong đó:

KiuDL kiểu liệu mà hàm trả Ta bỏ qua tùy chọn sử dụng tùy chọn RESULT

RECURSIVE tùy chọn để hàm hàm đệ qui TenHam tên của hàm, dùng để gọi tới hàm

(81)

TenKetQua tên biến chứa kết trả hàm Nếu sử dụng tùy chọn câu lệnh TenHam = không phép xuất Ngược lại, khơng sử dụng tùy chọn RESULT phải có dịng lệnh TenHam = để trả kết hàm

Hàm có thểđược gọi tới cách gán giá trị hàm cho biến, hàm tham gia vào biểu thức tính:

TenBien = TenHam ( [Các_đối_s] ) Ví dụ, câu lệnh

Cx = COS (x)

sẽ tính giá trị cosin x lời gọi hàm COS(x) gán cho biến Cx Còn câu lệnh Pi = 4.0 * ATAN (1.0)

giá trị arctan(1.0) tính thơng qua lời gọi hàm ATAN(1.0), sau lấy kết nhận nhân với 4.0 gán giá trị biểu thức cho biến Pi

Khi xây dựng hàm, Các_đối_s đối số hình thức, gọi hàm Các_đối_s

phải thay vào danh sách đối số thực Ví dụ, hàm YNewđược xây dựng với ba đối số hình thức X, Y, A:

FUNCTION YNew ( X, Y, A )

YNew =

END FUNCTION YNew

Khi hàm gọi tới, đối s hình thc được thay đối s thc: U =

V = Pi =

Y = YNew( U, V, Pi/2 )

Các đối số hình thức đối số thực phải tương ứng 1-1 thứ tự xuất kiểu

liệu chúng

4.3.2 Thủ tục (Internal SUBROUTINE)

Về cú pháp khai báo thủ tục giống với khai báo hàm Chỉ có số khác biệt sau:

− Khơng có giá trị liên kết với tên thủ tục

−Để gọi tới thủ tục phải dùng từ khóa CALL

− Từ khóa SUBROUTINEđược dùng đểđịnh nghĩa thủ tục thay cho từ khóa FUNCTION

− Hàm khơng có đối số sẽđược gọi tới cách thêm vào sau tên hàm cặp dấu ngoặc đơn rỗng ( ) (Ví dụ, MyFunction() ), thủ tục khơng có đối số gọi tới khơng cần cặp dấu ngoặc đơn (Ví dụ: CALL MySubroutine)

(82)

SUBROUTINE TenThuTuc [( Các_đối_số )] [Các_câu_lnh_khai_báo]

[Các_câu_lnh_thc_hin] END SUBROUTINE [TenThuTuc]

Trong Các_đối_s danh sách đối số hình thức, liệt kê cách dấu phẩy Lời gọi thủ tục:

CALL TenThuTuc [( Các_đối_s_thc )]

Trong danh sách đối số hình thức danh sách đối số thực phải tương ứng 1−1 với

Chú ý:

• Nói chung hàm chương trình trả giá trị: Giá trị hàm ứng với đối số (Sau ta thấy hàm trả nhiều giá trị)

• Trong định nghĩa hàm (FUNCTION), trước trả chương trình gọi, giá trị hàm

được xác định câu lệnh gán cho TenHam cho biến TenKetQua tùy chọn RESULT Đối với thủ tục kết sẽđược trả thơng qua danh sách

đối số, nhiệm vụ

• Hàm (và thủ tục) kết thúc câu lệnh END cuối Tuy nhiên sử dụng câu lệnh RETURN để trả chương trình gọi Khi gặp câu lệnh RETURN chương trình sẽđược giải phóng quay chương trình gọi, bất chấp sau có cịn câu lệnh thực hay không

4.4 CÂU LỆNH CONTAINS

Câu lệnh CONTAINS câu lệnh không thực hiện, dùng để phân cách thân chương trình (chính xác đơn vị chương trình) với chương trình thuộc Các chương trình xếp sau câu lệnh CONTAINS trước từ khóa END chương trình Bố

cục tổng qt chương trình có dạng sau PROGRAM TenChuongTrinh

[Các_câu_lnh_khai_báo] [Các_câu_lnh_thc_hin] [CONTAINS

Các_chương_trình_con_trong ] END [PROGRAM [TenChuongTrinh]]

Ởđây, Các_chương_trình_con_trong những hàm thủ tục chịu quản lý chương trình TenChuongTrinh Ví dụ, chương trình sau đây, CT_CHINH gọi đến chương trình có tên CT_CON

PROGRAM CT_CHINH REAL A(10)

(83)

CONTAINS

SUBROUTINE CT_CON (B) REAL B(10)

END SUBROUTINE CT_CON END PROGRAM CT_CHINH

4.5 MỘT SỐ VÍ DỤ VỀ CHƯƠNG TRÌNH CON TRONG Ví dụ 4.2 Tính tích phân xác định =∫b

a

dx ) x ( f

I phương pháp hình thang

Giả sử

2

2

1 x

e )

x (

f

π

= Ta chia khoảng (a; b) làm N đoạn Δx=(b−a)/N, xác định điểm chia x0=a, x1=x0+Δx, , xN=b; mỗi lần ta tính diện tích N hình thang xác định đáy f(xi), f(xi+Δx) chiều cao Δx Giá trị tích phân sẽđược xấp xỉ tổng diện tích N hình thang Rõ ràng, N lớn tổng diện tích hình thang tiệm cận tới giá trị tích phân Do độ xác phép xấp xỉ xác định sai số tương đối |((S2−S1)/S2) < ε|, S1 S2 tổng diện tích hình thang ứng với N=K N=K+1 Từđó ta có sơđồ tính lời chương trình sau

B1)Cho giá trị a, b (a<b), Epsilon

B2)Khởi tạo N=0, S1=0

B3)Tăng số khoảng chia lên 1: N = N+1

B4)Chia đoạn (a; b) làm N khoảng, với cự ly khoảng DelX = (b−a)/N

B5)Tính tổng diện tích N hình thang gán cho S2: 1) Gán S2=0

2) Lặp lại N lần, lần ứng với hình thang: j = 1, 2,…, N a) Xác định x1, x2, f(x1), f(x2): x1=a+(j−1)*DelX; x2=x1+DelX b) Tính diện tích hình thang thứ j: Tmp = (f(x1) + f(x2) ) * DelX / c) Cộng dồn diện tích hình thang vừa tính vào S2: S2=S2+Tmp

B6)Tính sai số: SS=ABS( (S2−S1)/S2)

B7)Kiểm tra điều kiện kết thúc:

1) Nếu SS < Epsilon: In kết kết thúc chương trình 2) Nếu SS >= Epsilon:

a) Lưu giá trị S2 vào S1: S1 = S2 b) Lặp lại từ bước B3)

(84)

REAL S1,S2,DELX

REAL X, F1,F2, SS,EP, HSO

REAL, PARAMETER :: EP=1.E-4, A=0., B=3 N=0

S1=0 DO N=N+1

DELX = (B-A)/REAL(N)/2.0 S2=0

DO J=1,N

X = A + (J-1)*DELX IF (J>1) THEN F1 = F2 ELSE F1= F(X) END IF X = X + DELX F2= F(X)

S2= S2 + (F1+F2)*DELX END DO

SS = ABS((S2-S1)/S2) IF (SS < EP ) EXIT S1 = S2

PRINT*,'SO HINH THANG =',N END DO

PRINT '('' GIA TRI TP = '',F10.4)', S2 CONTAINS

FUNCTION F(X) RESULT (Fr)

Fr=1.0/SQRT(2.0*(4.0*ATAN(1.)))*EXP(-0.5*X*X) END FUNCTION F

END

Trong chương trình trên, giá trị cận tích phân sai số cho phép khởi tạo thông qua lệnh khai báo hằng, F(X) hàm với đối số hình thức X Kết trả hàm lưu biến Frở tùy chọn RESULT

Ví dụ 4.3 Giải phương trình f(x) = phương pháp lặp Newton

Nội dung phương pháp lặp Newton giải phương trình f(x)=0 tóm tắt qua bước

sau

1) Khởi tạo nghiệm x giá trị ban đầu

2) Gán x x−f(x)/f’(x), f’(x) đạo hàm bậc f(x) 3) Tính kiểm tra điều kiện f(x) ~

− Nếu chưa thỏa mãn quay lại bước 2)

(85)

Giả sử cho f(x) = x3 + x − Khi đó f’(x) = 3x2 + Ta chọn giá trị khởi tạo của x Điều kiện để xem x nghiệm gần phương trình là: thỏa mãn f(x) < 10−6 hoặc số lần lặp lớn 20 Lời chương trình sau

PROGRAM Newton

! Giai PT f(x) = bang PP Newton IMPLICIT NONE

INTEGER :: Its = ! Dem lan lap

INTEGER :: MaxIts = 20 ! So lan lap cuc dai LOGICAL :: Converged = false ! Dieu kien hoi tu REAL :: Eps = 1E-6 ! Sai so cho phep

REAL :: X = ! Gia tri nghiem khoi tao DO WHILE (.NOT Converged AND Its < MaxIts) X = X - F(X) / DF(X)

PRINT*, X, F(X) Its = Its +

Converged = ABS( F(X) ) <= Eps END DO

IF (Converged) THEN PRINT*, 'Hoi tu' ELSE

PRINT*, 'Phan ky' END IF

PRINT*,’Nghiem PT: X = ‘,X CONTAINS

FUNCTION F(X) REAL F, X

F = X ** + X - END FUNCTION F FUNCTION DF(X) REAL DF, X DF = * X ** + END FUNCTION DF END PROGRAM Newton

Trong chương trình trên, hàm F(X) DF(X) trả thông qua lệnh gán TenHam = …, khác với ví dụở mục trước giá trị hàm trả thơng qua biến tùy chọn RESULT

Ví dụ 4.4 In một dãy ký tự giống

Chương trình sau cho phép in dãy ký tự giống nhau, số lượng ký tự cho ởđối số thứ mã ASCII ký tựđược cho ởđối số thứ hai thủ tục DayKyTu IMPLICIT NONE

CALL DayKyTu( 5, 65 ) ! chu A lien tuc CONTAINS

SUBROUTINE DayKyTu ( Num, Symbol ) INTEGER I, Num, Symbol

(86)

DO I = 1, Num

Line(I:I) = ACHAR( Symbol ) END DO

PRINT*, Line END SUBROUTINE END

Câu lệnh Line(I:I) = ACHAR( Symbol ) chương trình có nghĩa gán ký tự thứ I xâu Line ký tựACHAR( Symbol )

Nhưđã thấy, thủ tục DayKyTu nhận hai tham số đầu vào (5 ký tự) 65 (ký tự

thứ 65 bảng mã ASCII − chữ A) truyền cho đối số tương ứng Num Symbol Kết

của lời gọi thủ tục in chữ A liên tục Ví dụ 4.5 Tính tổ hợp chập

)! k n ( ! k

! n Cnk

=

Để tính tổ hợp chập cần phải xây dựng hàm tính giai thừa Chương trình sau tính in tổ hợp chập từ đến 10 10

PROGRAM TOHOPCHAP INTEGER I

DO I = 0, 10

PRINT*, I, Fact(10)/(Fact(I)*Fact(10-I)) END DO

CONTAINS

FUNCTION Fact ( N ) INTEGER Fact, N, Temp , I Temp =

DO I = 2, N Temp = I * Temp END DO

Fact = Temp END FUNCTION END

4.6 BIẾN TOÀN CỤC VÀ BIẾN ĐỊA PHƯƠNG

Hãy xét hai chương trình đây, mục đích chương trình tính in giai thừa số từ đến 10 Ta để ý đến khác chúng

Ví dụ 4.6 PROGRAM VER1 INTEGER I DO I = 1, 10

PRINT*, I, Fact(I) END DO

CONTAINS

(87)

DO I = 2, N Temp = I * Temp END DO

Fact = Temp END FUNCTION END

PROGRAM VER2 INTEGER I DO I = 1, 10

PRINT*, I, Fact(I) END DO

CONTAINS

FUNCTION Fact ( N ) INTEGER Fact, N, Temp, I Temp =

DO I = 2, N Temp = I * Temp END DO

Fact = Temp END FUNCTION END

Khi chạy chương trình ta thấy hai chương trình viết gần hồn tồn giống nhau, kết lại khác Vì vậy? Vấn đềở chỗ có mặt biến I câu lệnh khai báo chương trình Fact:

INTEGER Fact, N, Temp, I

Vì chương trình Factlà chương trình trong, nên biến I khơng khai báo,

sử dụng biến khai báo chương trình điều khiển Như vậy, chương trình VER1, biến Iđồng thời bịđiều khiển chương trình lẫn chương trình Tác động trình dùng chung biến I có thểđược mơ tả sau

− Khi chương trình (CTC) biến I=1, truyền tham sốN=I=1 cho chương trình (FACT), đồng thời FACT, biến I=2, 1 nên Fact=Tmp=1 (Vịng DO khơng thực hiện) Khi FACT trả vềCTC thì I=2

− Sau FACT trả CTC biến I tăng lên biến điều khiển chu trình DO: I=I+1=2+1=3, giá trị lại truyền cho FACT, nên N=I=3, đồng thời FACT, I=2, 3

đó Fact=1.2.3=6 (Ra khỏi vịng DO FACT: I=N+1 = 3+1 =4) Khi FACT trả vềCTC I=4

− Tiếp tục, CTC: I=I+1=4+1=5; truyền tham số cho FACT N=I=5, FACT: I=2, 5 nên Fact = 1.2.3.4.5 = 120 (Ra khỏi vòng DO FACT: I=N+1=5+1=6) FACT lại trả vềCTC giá trị I=6

(88)

Nhưng, chương trình ta khai báo thêm biến I, nhưở chương trình VER2, q trình tính tốn diễn xác chương trình kết thúc bình thường

Biến I khai báo chương trình gọi biến tồn cục, cịn biến I khai báo chương trình biến địa phương Các chương trình phép tham chiếu đến biến toàn cục biến địa phương không khai báo Tuy nhiên, chương trình khơng tham chiếu đến biến địa phương khai báo chương trình

4.7 ĐỊNH NGHĨA HÀM BẰNG CÂU LỆNH ĐƠN

Hàm định nghĩa cấu trúc hàm nhưđã thấy mục 4.3.1, hàm có thểđược định nghĩa câu lệnh khai báo hàm Ta xét ví dụ sau

PROGRAM BT_HAM1 REAL X

F(x) = 3*x**2 - 5*x + Print*,' Cho gia tri cua X: ' Read*,x

Print '('' Gia tri ham F(x)='',F10.3)', F(x) END

Trong chương trình trên, câu lệnh F(x) = 3*x**2 - 5*x +

là cách định nghĩa hàm F(x) gọi biểu thức hàm, hay hàm lệnh (Statement function),

dùng lệnh gán đểđịnh nghĩa hàm Chương trình tương đương với chương trình sau PROGRAM BT_HAM2

REAL X

Print*,' Cho gia tri cua X: ' Read*,x

Print '('' Gia tri ham F(x)='',F10.3)', F(x) CONTAINS

FUNCTION F(X) F = 3*x**2 - 5*x + END FUNCTION END

Định nghĩa hàm biểu thức hàm cho phép làm đơn giản hóa việc viết chương trình Tuy nhiên, cách định nghĩa nhiều lúc gây khó khăn gỡ rối chương trình, chương trình lớn trình xây dựng, phát triển Bởi ta không nên sử dụng cách

định nghĩa chương trình chưa thực sựổn định 4.8 CHƯƠNG TRÌNH CON NGỒI

(89)

Các chương trình tồn dạng file độc lập gọi chương trình ngồi Chúng tham chiếu nhiều đơn vị chương trình khác Tuy nhiên, chương trình ngồi tồn file với chương trình

đơn vị chương trình khác khơng nằm câu lệnh CONTAINS END Trong trường hợp đó, đơn vị chương trình chứa file khác khơng thể tham chiếu trực tiếp đến chúng

được

Các chương trình ngồi có chương trình riêng chúng Nhưng chương trình lại khơng được phépchứa chương trình khác

Cú pháp khai báo chương trình ngồi có dạng 1) Khai báo hàm:

[KiuDL][RECURSIVE] FUNCTION TenHam ([Các_đối_s]) [RESULT (TenKetQua)] [Các_câu_lnh_khai_báo]

[Các_câu_lnh_thc_hin] [CONTAINS

Các_chương_trình_con_trong ] END [FUNCTION [TenHam] ]

2) Khai báo thủ tục:

SUBROUTINE TenThuTuc [( Các_đối_s )] [Các_câu_lnh_khai_báo]

[Các_câu_lnh_thc_hin] [CONTAINS

Các_chương_trình_con_trong] END [SUBROUTINE [TenThuTuc] ]

Như thấy, khai báo chương trình ngồi tương tự khai báo chương trình trong, ngoại trừ chương trình ngồi phép chứa chương trình trong, cịn chương trình khơng phép chứa chương trình khác Việc tham chiếu

đến chương trình ngồi hồn tồn tương tự tham chiếu đến chương trình Nghĩa giá trị hàm gán trực tiếp cho biến phận biểu thức, cịn thủ tục gọi đến từ khóa CALL Danh sách đối số lời gọi hàm thủ tục phải danh sách đối số thực Ví dụ, ta có hàm tính tổng hai số nguyên sau đây:

INTEGER FUNCTION Tong(a, b) RESULT (X) Integer a,b

X = a + b

END FUNCTION Tong

Khi hàm có thểđược tham chiếu sau: PROGRAM GOI_HAM

IMPLICIT NONE Integer I,j,N,M,Tong I = 10

J = 23

(90)

print*,N, M END

4.8.1 Câu lệnh EXTERNAL

Để tránh nhầm lẫn việc sử dụng chương trình thư viện Fortran chương trình ngồi có tên trùng nhau, ta nên khai báo tên các chương trình ngồi câu lệnh EXTERNAL Ta xét hai ví dụ minh họa sau

Ví dụ 4.7 Chương trình sau định nghĩa chương trình ngồi COS(X) có tên trùng với hàm COS(X) thư viện Fortran Khi chạy chương trình ta thấy chương trình khơng gọi tới, mà thay cho nó, hàm COS(X) Fortran sẽđược gọi

PROGRAM EXT1 REAL A

PRINT*,'Cho so A:' READ*, A

A = COS( A ) PRINT*, A END

FUNCTION COS( X ) COS = X + END FUNCTION

Ví dụ 4.8 Cũng chương trình đây, ta thêm câu lệnh EXTERNAL COS

vào phần khai báo chương trình, kết chương trình ngồi sẽđược gọi tới PROGRAM EXT2

REAL A

EXTERNAL COS PRINT*,'Cho so A:' READ*, A

A = COS( A ) PRINT*, A END

FUNCTION COS( X ) COS = X + END FUNCTION

Như vậy, trình xây dựng chương trình, ta cần phải thận trọng đặt tên cho chương trình ngồi Biện pháp an tồn khơng chắn tên chương trình khơng trùng với tên chương trình khác nên khai báo chúng câu lệnh EXTERNAL

4.8.2 Khai báo khối giao diện (INTERFACE BLOCK)

(91)

cho trình biên dịch tên chương trình ngồi, cho phép tìm liên kết (LINK) Tuy nhiên, để trình biên dịch tạo lời gọi chương trình ngồi cách xác, ngồi tên ra, cần phải biết chắn thơng tin chương trình con, số biến kiểu biến, Tập hợp thơng tin gọi phần giao diện chương trình

Đối với chương trình trong, chương trình modul, chương trình thư viện Fortran, phần giao diện ln trình biên dịch hiểu Nhưng trình biên dịch phát sinh lời gọi

đến chương trình ngồi, thơng tin thuộc phần giao diện hồn tồn chưa sẵn có, tức

ở trạng thái ẩn (implicit), nhiều trường hợp phức tạp (như đối số tùy chọn đối số

từ khóa) địi hỏi phải cung cấp thơng tin giao diện đầy đủ Do cần có khối giao diện Khai báo khối giao diện sau

INTERFACE

Thân_ca_khi_giao_din

END INTERFACE

Trong Thân_ca_khi_giao_din nên được chép cách xác phần đầu (header) chương trình con, khai báo đối số kết chúng, câu lệnh END chúng

Ví dụ 4.9 Chương trình sau gọi đến thủ tục ngồi có tên DOI_CHO Không quan trọng thủ tục nằm file hay khác file với chương trình chính, thơng tin

bản cần phải khai báo khối giao diện đầu chương trình để tham chiếu cách xác chương trình phát sinh lời gọi đến

IMPLICIT NONE

! Phan khai bao khoi giao dien INTERFACE

SUBROUTINE DOI_CHO( X, Y ) REAL X, Y

END SUBROUTINE END INTERFACE

! Phan khai bao bien, hang REAL A, B

! Than chuong trinh PRINT*,’ CHO SO: ‘ READ*, A, B

print*,A, B

CALL DOI_CHO ( A, B ) print*,A, B

END

! Chuong trinh ngoai

SUBROUTINE DOI_CHO ( X, Y ) ! Đổi giá trị hai biến REAL X, Y

(92)

END SUBROUTINE

4.9 CÁC THUỘC TÍNH CỦA ĐỐI SỐ

4.9.1 Thuộc tính INTENT

Khi thực lời gọi đến chương trình con, đối số hình thức thay

đối số thực chương trình gọi Quá trình tương tác đối số hình thức đối số thực

nhớđược mô tả sau Trước hết, trình biên dịch cấp phát nhớ cho tất đối số hình thức biến khai báo chương trình cách độc lập với nhớ dành cho biến

chương trình gọi (trừ biến, khai báo dùng chung (COMMON) trình bày sau) Sau

đó, nội dung đối số thực từ chương trình gọi sẽđược chép cách tương ứng sang

đối số hình thức Chương trình tiến hành q trình xử lý tính tốn biến mà trình biên dịch cấp phát nhớ cho Kết thúc tính tốn, trước trả chương trình gọi, nội dung

đối số hình thức sẽđược chép lại cách tương ứng sang đối số thực Sau trả kết

cho chương trình gọi tồn vùng nhớ dành cho đối số hình thức biến chương trình sẽđược giải phóng Như vậy, nhiều trường hợp, giá trị biến đầu vào từ chương trình gọi bị làm thay đổi cách không cố ý thông qua việc làm thay đổi giá trị đối số hình thức chương trình Điều gây nên hậu nghiêm trọng Để tránh nhầm lẫn đáng tiếc này, ta sử dụng từ khóa INTENT phần khai báo chương trình Cú pháp tác động từ khóa sau

INTENT (Mô_t) [::] vname

hoặc

Kiu_DL, INTENT (Mơ_t) :: vname

Trong đó, vname danh sách biến đóng vai trị đối số hình thức chương trình con; Kiu_DL kiểu liệu vname; Mơ_t nhận giá trị:

IN: Xác định vname tham số truyền vào cho chương trình con, khơng thể bị làm thay

đổi giá trị

OUT: Xác định vname biến trả giá trị chương trình gọi, cần phải có mặt danh sách đối số hình thức

INOUT: Xác định vname vừa tham số truyền vào cho chương trình vừa biến trả giá trị

về cho chương trình gọi, nghĩa vừa cung cấp thơng tin đầu vào cho chương trình vừa

trả kết cho chương trình gọi Do giá trị bị làm thay đổi Ví dụ, xét chương trình sau:

REAL X(20), SUM

CALL RANDOM_NUMBER (X) ! Tạo mảng số ngẫu nhiên X PRINT*,X ! X truyền cho chương trình

CALL TONG (X,20,SUM)

(93)

SUBROUTINE TONG (X,N,SUM)

INTEGER, INTENT (IN) :: N ! N chỉ IN

REAL, INTENT (INOUT) :: X(N) ! X vừa IN vừa OUT REAL, INTENT (OUT) :: SUM ! SUM chỉ OUT X = X + 10 ! Làm thay đổi X

SUM = DO I=1,N

SUM=SUM+X(I) END DO

END SUBROUTINE TONG END

Trong chương trình trên, RANDOM_NUMBER chương trình thư viện Fortran, dùng để tạo số ngẫu nhiên Đối số hàm biến đơn biến mảng Vì biến N

chương trình tham số truyền vào, nên ta làm thay đổi giá trị nó; X vừa biến truyền vào, vừa biến kết xuất nên bị thay đổi; cịn SUM biến kết xuất

4.9.2 Thuộc tính OPTIONAL

Một tình khác xảy xây dựng chương trình danh sách đối số

hình thức nhiều, khơng phải lúc ta tham chiếu đến tất đối số lời gọi Đôi ta cần tham chiếu đến vài số đối số chương trình Để

tránh việc tham chiếu đến đối số khơng cần thiết ta khai báo chương trình tất số đối số có thuộc tính tùy chọn Từ khóa dùng để khai báo đối số tùy chọn OPTIONAL mà cú pháp cách sử dụng mô tả sau

OPTIONAL [::] vname

hoặc

Kiu_DL, OPTIONAL :: vname

Trong đó, vname danh sách biến đóng vai trị đối số hình thức chương trình con; Kiu_DL kiểu liệu vname Để minh họa ta xét ví dụ sau Giả sử ta có chương trình ngồi:

SUBROUTINE TONG (X,N,SUM, A, B, C, D, E) INTEGER, INTENT (IN) :: N

REAL, INTENT (INOUT) :: X(N) REAL, INTENT (OUT) :: SUM

REAL, OPTIONAL :: A, B, C, D, E ! Các đối số tùy chọn X = X + 10

SUM = DO I=1,N

SUM=SUM+X(I) END DO

(94)

D = X(3) E = C * D

END SUBROUTINE TONG

Chương trình ngồi TONG chứa đối số hình thức, có đối số tùy chọn (có thuộc tính OPTIONAL), chúng xuất khơng lời gọi chương trình gọi Giả

sử chương trình ta khai báo khối giao diện cho chương trình là: INTERFACE

SUBROUTINE TONG (X,N,SUM, A, B, C, D, E) REAL, INTENT (INOUT) :: X(N)

REAL, OPTIONAL :: A, B, C, D, E END SUBROUTINE TONG

END INTERFACE

Khi chương trình TONG có thểđược gọi đến sau: CALL TONG (X,N,SUM) ! Bỏ qua tất đối số tùy chọn CALL TONG (X,N,SUM, T) ! Bỏ qua đối số tùy chọn cuối CALL TONG (X,N,SUM, T, U) ! Bỏ qua đối số cuối

Trong trường hợp trên, danh sách đối số xuất theo trình tự xuất chúng khai báo chương trình con; đối số bị bỏ qua nằm cuối danh sách Tuy nhiên ta sử dụng lời gọi đối số bị bỏ qua vị trí Khi cần phải dùng phép “gán” cho đối số muốn xuất Chẳng hạn:

CALL TONG (X,N,SUM, B=T) ! Bỏ qua đối số thứ 4, 6,7,8 CALL TONG (X,N,SUM, C=T, E=U) ! Bỏ qua đối số thứ 4,5,7

Nếu đối số tùy chọn “gán” đối số nằm sau thiết phải “gán”, dù chúng tham chiếu theo trình tự xuất Ví dụ câu lệnh gọi chương trình sau sai:

CALL TONG (X,N,SUM, B=T, U, V, Y) ! Sai Câu lệnh là:

CALL TONG (X,N,SUM, B=T, C=U, D=V, E=Y)

4.9.3 Thuộc tính SAVE

Nhưđã đề cập mục 4.9.1, vùng nhớ cung cấp cho biến địa phương chương trình giải phóng sau chương trình trả kết cho chương trình gọi Và vậy, giá trị biến trở nên không xác định lần gọi tới chương trình Nếu muốn lưu giữ giá trị chúng cho lần gọi sau ta có thểđặt thuộc tính SAVE cho chúng Khi biến chương trình đặt thuộc tính SAVE, giá trị bảo lưu cho lần gọi Cú pháp khai báo thuộc tính SAVE sau:

SAVE [::] vname

(95)

Kiu_DL, SAVE :: vname

Trong đó, vname danh sách biến địa phương chương trình khơng phải đối số hình thức; Kiu_DL kiểu liệu vname

4.10 MODUL

Fortran định nghĩa khái niệm đơn vị chương trình (Program Unit) là: chương trình chính, chương trình ngồi, modul Modul khác với chương trình điểm quan trọng:

Modul có thể chứa nhiều chương trình (được gọi chương trình modul);

− Modul chứa câu lệnh khai báo đặc tả mà chúng tham chiếu tất đơn vị chương trình có sử dụng modul

Các modul có thểđược biên dịch cách độc lập Cấu trúc chung modul có dạng

sau:

MODULE TenModul

[Các_câu_lnh_khai_báo] [CONTAINS

Các_chương_trình_con_modul] END [MODULE [TenModul]]

Để sử dụng modul ta dùng câu lệnh khai báo USE đầu chương trình: USE Tên_Modul_được_s_dng

Như vậy, cấu trúc modul giống cấu trúc chương trình ngồi, trừ từ khóa SUBROUTINE FUNCTION Modul có chương trình Modul sử dụng modul khác Vì modul chứa câu lệnh khai báo để tất

các đơn vị chương trình khác truy cập tới, nên biến tồn cục có thểđược khai báo theo cách cho chương trình sử dụng modul Tính chất hữu ích để tạo khai báo phức tạp, kiểu liệu người dùng định nghĩa,… Các khối giao diện có thểđược gộp vào modul

Ví dụ 4.10 Chương trình sau sử dụng modul MyModul mà nội dung chứa tham sốPI thủ tục DOI_CHO Trong chương trình ta cần khai báo USE MyModul đủ để sử dụng tham số PI lời gọi đến thủ tục DOI_CHO Nói chung modul MyModul nên

được lưu file tách biệt với file chương trình PROGRAM EXAMP

USE MyModul IMPLICIT NONE REAL A, B

PRINT*, ‘ Cho mot so: ‘ READ*, A

B = Pi ! Khai bao tu Modul

(96)

PRINT*, A, B END

MODULE MyModul

REAL, PARAMETER :: Pi = 3.1415927 CONTAINS

SUBROUTINE DOI_CHO ( X, Y ) REAL Tmp, X, Y

Tmp = X X = Y Y = Tmp

END SUBROUTINE DOI_CHO END MODULE MyModul 4.11 PHÉP ĐỆ QUI

Trong nhiều trường hợp phép đệ qui cho phép làm đơn giản hố chương trình cách đáng kể Có thể xem phép đệ qui hàm hay thủ tục tham chiếu đến Phép đệp qui bao gồm hai thành phần: Phần neo, tác động hàm hay thủ tục đặc tả cho hay nhiều tham số, phần đệ qui tác động cần thực cho giá trị thời tham số xác định tác động hay giá trịđược định nghĩa trước

Ví dụđiển hình cho phép đệ qui hàm thủ tục tính giai thừa Xuất phát từđịnh nghĩa n! ta có: 0! = 1! = 1, với n>0 n! = n.(n−1)! Đây công thức truy hồi, tức biết (n−1)! tính n! Ta có hàm thủ tục tính n! sau:

RECURSIVE FUNCTION GIAITHUA1 ( N ) RESULT (Fact) INTEGER Fact, N

IF( N == OR N == ) THEN ! Phan neo Fact =

ELSE ! phan de qui Fact = N * GIAITHUA1( N-1 ) END IF

END FUNCTION Hoặc

RECURSIVE SUBROUTINE GIAITHUA2( F, N ) INTEGER F, N

IF (N == OR N == 1) THEN ! Phan neo F =

ELSE ! Phan de qui CALL GIAITHUA2( F, N-1 ) F = N * F

END IF

END SUBROUTINE

(97)

Một ví dụ khác, trung bình số học dãy số x1, x2, , xn tính theo cơng thức: n

x = ∑

= n i i x n 1

Ta biểu diễn cơng thức dạng khác: xn = ((n−1).xn−1 + xn)/n, đó

1

n

x trung bình n−1 thành phần đầu dãy Phần neo xác định định nghĩa sau:

− Số thành phần n>0

− Nếu n=1 xn = x1,

− Nếu n=2 xn = (x1 + x2)/2

Bạn đọc viết chương trình đệ qui cho tốn tập BÀI TẬP CHƯƠNG

4.1 Làm tập 3.5 3.6 chương hàm f(x) viết dạng chương trình

4.2 Viết chương trình tính sine x theo công thức: ! 7 ! 5 ! 3 sin + − + −

=x x x x

x

với độ xác ε=10−4 Sử dụng chương trình hàm để tính giai thừa

4.3 Viết chương trình tính cosine x theo cơng thức: ! 6 ! 4 ! 2 cos + + +

= x x x

x

với độ xác ε=10−4 Sử dụng chương trình hàm để tính giai thừa

4.4 Viết chương trình tìm nghiệm phương trình x2sinx + cos2x = đoạn [−2; 2] bằng phương pháp chia đơi u cầu xây dựng chương trình hàm thủ tục Lấy độ xác nghiệm đến 10−6 Gợi ý: Sử dụng định lý: Hàm số y=f(x) có f(a).f(b)<0 tồn tại x=c thuộc (a;b)

cho f(c)=0

4.5 Viết chương trình tính đạo hàm hàm số y=f(x) x=x0 với độ xác đến 10−6 Yêu cầu xây dựng chương trình hàm để tính f(x) Lấy ví dụ f(x)=2x2, x

0=1 Gợi ý: Đạo hàm hàm số y=f(x) x=x0 có thểđược tính theo cơng thức (f(x0+h) f(x0))/h h0

4.6 Viết chương trình hàm tính ex theo cơng thức khai triển chuỗi Taylor: ! 3 ! 2 1 + + + +

= x x x

(98)

4.7 Viết chương trình xây dựng hàm tính tổ hợp chập k n theo công thức:

)! ( !

! k n k

n Ck

n = −

Chương trình cho phép kiểm tra lỗi vào liệu không hợp lệ Ví dụ, cho k n số

âm, k>n, chương trình sẽđưa thông báo lỗi “Dữ liệu không hợp lệ” kết thúc

4.8 Viết chương trình dạng thủ tục giải phương trình ax2 + bx + c = Chương trình cho phép đưa nghiệm ảo biệt thức Delta <

4.9 Viết chương trình dạng thủ tục xác định dãy n số Fibonacci (xem tập 3.13) 4.10 Hàm Laplas định nghĩa Φ(x) = e dt

x t ∫ −

5

2

π Viết chương trình dạng hàm

tính giá trị Φ(x) Thử chạy chương trình với vài giá trị x, chẳng hạn x=1.96, x=3.0 4.11 Ba hàm đa thức Legendre có dạng P0(x)=1, P1(x)=x, P2(x)=(3x21)/2 Công thức truy hồi để xác định hàm đa thức Legendre

0 ) ( )

( ) 1 2 ( ) ( ) 1

(n+ Pn+1 xn+ xPn x +nPn−1 x =

Ký hiệu hàm thứ n đa thức Legendre P(N, X) = Pn(x) Viết chương trình dạng thủ tục xác định giá trị hàm P1(x), , Pn(x) của đa thức cho giá trị n x

4.12 Cũng với điều kiện nhưở tập 4.11 Hãy viết chương trình dạng hàm tính giá trị

(99)

CHƯƠNG MẢNG 5.1 KHÁI NIỆM VỀ MẢNG TRONG FORTRAN

Có thểđịnh nghĩa mảng tập hợp phần tử có kiểu liệu, xếp theo trật tự định, phần tửđược xác định số giá trị chúng Chỉ số phần tử mảng xem “địa chỉ” phần tử mảng mà dùng để truy cập/tham chiếu đến phần tử mảng Mỗi phần tử mảng xác định “địa chỉ” mảng Mảng mảng chiều nhiều chiều Mảng chiều hiểu vectơ mà phần tử mảng thành phần vectơ Địa phần tử mảng chiều xác định số số thứ tự chúng mảng Mảng hai chiều hiểu ma trận mà địa phần tử xác định hai số: số thứ số thứ tự hàng, số thứ hai số thứ tự cột Tương tự, mảng ba chiều xem tập hợp mảng hai chiều, phần tử mảng xác định ba số: số thứ nhất, số thứ hai (tương ứng hàng cột ma trận) số thứ ba (lớp − số thứ tự ma trận),

Kiểu liệu phần tử mảng kiểu số số Mỗi mảng xác

định tên mảng, số chiều, kích thước cực đại cách xếp phần tử mảng Tên mảng gọi tên biến mảng, hay ngắn gọn biến mảng Biến mảng biến có chiều

Mảng mảng tĩnh mảng động Nếu mảng tĩnh vùng nhớ dành lưu trữ

mảng cố định khơng bị giải phóng chừng chương trình cịn hiệu lực Kích thước mảng tĩnh khơng thể bị thay đổi trình chạy chương trình Nếu mảng mảng động, vùng

nhớ lưu trữ có thểđược gán, thay đổi giải phóng chương trình thực

Các trỏ (POINTER) biến động Nếu trỏ mảng kích thước chiều bị thay đổi lúc chương trình chạy, giống mảng động Các trỏ trỏđến biến mảng biến vô hướng

5.2 KHAI BÁO MẢNG

Để sử dụng mảng thiết cần phải khai báo Khi khai báo mảng cần phải tên số

chiều nó, chưa cần kích thước cách xếp phần tử mảng Có nhiều cách khai báo biến mảng Sau liệt kê số trường hợp ví dụ

(100)

POINTER C(:, :, :) ! Mảng số thực chiều

REAL,DIMENSION (2,5) :: D ! Mảng số thực chiều REAL,ALLOCATABLE :: E(:,:,:)! Mảng thực chiều REAL, POINTER :: F(:,:) ! Mảng số thực chiều

Trong ví dụ trên, mảng A(10, 2, 3) mảng ba chiều gồm phần tử có kiểu số thực loại byte, kích thước cực đại mảng 10 x x = 60 phần tử, dung lượng nhớ cấp phát cho mảng 60 x (byte) = 240 byte, cách xếp phần tử 10 hàng, cột lớp, địa hàng, cột lớp đánh số từ (hàng đến hàng 10, cột đến cột 2, lớp đến lớp 3) Mảng B mảng động chiều, kích thước cách xếp phần tử chưa xác định Mảng C mảng thực ba chiều có kiểu trỏ Ta thấy rằng, sử dụng từ khóa khai báo kiểu, khai báo thuộc tính đểđịnh nghĩa mảng, kết hợp từ khóa khai báo kiểu khai báo thuộc tính Khi có kết hợp khai báo kiểu khai báo thuộc tính, chúng cần phải phân tách dấu phẩy sau từ khóa thuộc tính phải có hai dấu hai chấm liền phân tách chúng với tên biến Số chiều, kích thước cách xếp phần tử mảng định nghĩa với từ khóa thuộc tính tên biến

Cách đánh sốđịa phần tử mảng đặc điểm quan trọng, định cách truy cập đến phần tử mảng Chỉ số xác định địa phần tử mảng phụ

thuộc vào giới hạn giới hạn dùng để mô tả cách xếp phần tử theo chiều mảng Ví dụ, hai mảng

INTEGER M(10, 10, 10) INTEGER K(-3:6, 4:13, 0:9)

đều có kích thước (10 x 10 x 10), mảng M có số phần tử mảng theo ba chiều biến thiên từ đến 10 (giới hạn 1, giới hạn 10), cịn mảng K có số phần tử

mảng biến thiên theo chiều thứ (hàng) −3 đến 6, theo chiều thứ hai (cột) đến 13 theo chiều thứ ba (lớp) đến Như vậy, giới hạn số phần tử mảng K tương ứng

−3, 0, giới hạn 6, 13 Các mảng mô tả rõ ràng gọi mảng có mơ tả tường minh

Đối với mảng mô tả không tường minh, cách xếp đánh số địa phần tử mảng thường xác định lúc chương trình chạy truyền qua tham số chương trình Ví dụ:

REAL X (4, 7, 9)

CALL SUB1(X) CALL SUB2(X)

END

SUBROUTINE SUB1(A) REAL A(:, :, :)

(101)

END SUBROUTINE SUB1 SUBROUTINE SUB2(B) REAL B(3:, 0:, -2:)

END SUBROUTINE SUB2

Ởđây, mảng A chương trình SUB1 là: A (4, 7, 9)

còn mảng B chương trình SUB2 là: B (3:6, 0:6, -2:6)

Nói chung có nhiều cách khai báo mảng khác tùy thuộc vào yêu cầu bối cảnh cụ

thể Sau số dạng cú pháp tổng quát câu lệnh khai báo mảng thường sử dụng lập trình

Dạng 1:

Kiu_DL Tên_biến_mảng (Mơ_t) Dạng 2:

Thuộc_tính Tên_biến_mảng (Mơ_t) Dạng 3:

Kiu_DL, Thuộc_tính (Mơ_t) :: Tên_biến_mảng Dạng 4:

Kiu_DL, Thuộc_tính :: Tên_biến_mảng(Mơ_t)

Trong Kiu_DL kiểu liệu phần tử mảng, Thuộc_tính có thể thuộc tính DIMENSION, ALLOCATABLE, POINTER,…, Tên_biến_mảng tên biến mảng (nếu có nhiều biến chúng liệt kê cách dấu phẩy), Mô_t mô tả

số chiều, kích thước mảng cách xếp phần tử mảng Nếu mơ tả ẩn cách xếp phần tử mảng chưa cần khai báo biến mảng Ví dụ:

Dạng 1: REAL*4 X (0:100) REAL Y(12,34)

Dạng 2:

DIMENSION N (10,20) ALLOCATABLE Y(:,:)

Dạng 3:

REAL, ALLOCATABLE(:,:) :: X

INTEGER, DIMENSION(12,34) :: Y Dạng 4:

REAL, ALLOCATABLE :: X (:,:)

(102)

5.3 LƯU TRỮMẢNG TRONG BỘ NHỚ VÀ TRUY CẬP ĐẾN CÁC PHẦN TỬ MẢNG

Nguyên tắc lưu trữ mảng nhớ Fortran lưu trữ dạng vectơ, cho dù mảng chiều hay nhiều chiều Đối với mảng chiều, phần tử mảng xếp theo thứ tự

từ phần tử có địa mảng (chỉ số) nhỏ đến phần tử có địa lớn Các phần tử mảng hai chiều xếp thành vectơ, “đoạn” liên tiếp vectơ cột với số

cột tăng dần Các mảng ba chiều xem tập hợp mảng hai chiều với số thứ tự mảng hai chiều (số thứ tự lớp) số thứ ba mảng Các mảng nhiều chiều lưu trữ theo ngun tắc Nói xác hơn, tùy thuộc vào số chiều mảng mà xếp phần tử mảng, số chiều thứ biến đổi trước, tiếp đến chiều thứ hai, chiều thứ ba, Các phần tử mảng truy cập đến qua địa chúng mảng

Để rõ ta xét số ví dụ sau Ví dụ 5.1 Mảng chiều Giả sử ta khai báo

REAL X(5), Y(0:5)

Khi mảng X Yđược xếp nhớ sau:

X(1) X(2) X(3) X(4) X(5) Y(0) Y(1) Y(2) Y(3) Y(4) Y(5) Chương trình sau minh họa cách truy cập đến phần tử mảng REAL X(5), Y(0:5)

Y(0) = DO I=1,5

X(I) = I*I ! Gán giá trị cho phần tử X Y(I) = X(I) + I

! Nhận giá trị phần tử X, tính tốn

! gán cho phần tử Y END DO

PRINT ‘(6F7.1))’, (X(I), I=1,5) ! In phần tử X PRINT ‘(6F7.1))’, (Y(I), I=0,5) ! In phần tử Y END

Khi chạy chương trình ta nhận kết hình là: 1.0 4.0 9.0 16.0 25.0

1.0 2.0 6.0 12.0 20.0 30.0 Ví dụ 5.2 Mảng hai chiều Giả sử ta khai báo

INTEGER, PARAMETER :: N=3, M=4 INTEGER A(N, 0:M)

(103)

⎟ ⎟ ⎟ ⎠ ⎞ ⎜ ⎜ ⎜ ⎝ ⎛ = ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A ) , ( A A 4 3 3 3 2 2 1 1

A lưu trữ nhớ dạng:

Ví dụ 5.3 Mảng ba chiều

Giả sử mảng A khai báo

INTEGER, PARAMETER :: NH=3, MC=4, LLayer=3 INTEGER A(0:NH, MC, LLayer)

Khi A mảng ba chiều gồm hàng, cột lớp, có cấu trúc sau:

Và lưu trữ nhớ dạng:

Sau số ví dụ truy cập mảng Nếu mảng Ađược khai báo REAL A(5,10), B(5,10) Khi đó:

A = 3.0 ! Gán tất phần tử A A(1,1) = ! Gán phần tử hàng 1, cột 4.,

(104)

A(2,1:8:3)=2.5 ! Gán phần tử cột 1, 4, hàng 2.5 Tức A(2,1) = A(2,4) = A(2,7) = 2.5 Các số1:8:3 chiều thứ hai tương đương với vòng lặp DO J=1, 8, 3

B = SQRT(A) ! Gán tất phần tử B ! bậc hai phần tử tương ứng A Nếu khai báo

REAL A(10) Khi đó: A(1:5:2)=3.0

!Gán phần tử A(1), A(3), A(5) 3.0 A(:5:2)=3.0 ! Tương tự câu lệnh

A(2::3)=3.0

! Gán phần tử A(2), A(5), A(8) 3.0

(Chỉ số cao ngầm định 10 kích thước cực đại A, tương đương với vòng lặp DO I=2, 10, 3)

A(7:9) = 3.0 ! Gán phần tử A(7), A(8), A(9) 3.0 ! (Bước vòng lặp ngầm định 1)

A(:) = 3.0 ! Tương tự A = 3.0; Một ví dụ khác, có khai báo REAL A(10), B(5, 5)

INTEGER I(4), J(3)

ta gán giá trị cho phần tử mảng I J cách: I = (/ 5, 3, 8, /)

J = (/ 3, 1, /) Còn câu lệnh

A(I) = 3.0

có nghĩa gán phần tử A(5), A(3), A(8) A(2) 3.0, câu lệnh B(2,J) = 3.0

là gán phần tử B(2,3), B(2,1) B(2,5)

Qua ví dụ ta thấy cách truy cập đến phần tử mảng Fortran mềm dẻo linh hoạt Đó “thế mạnh” ngôn ngữ lập trình

5.3.1 Sử dụng lệnh DATA để khởi tạo mảng

(105)

REAL, DIMENSION(10) :: A, B, C(3,3) DATA A / 5*0, 5*1 /

! Gán phần tửđầu phần tử DATA B(1:5) / 4, 0, 5, 2, -1 /

! Chỉ gán giá trị cho phần tử từ B(1) đến B(5) DATA ((C(I,J), J= 1,3), I=1,3) /3*0,3*1, 3*2/ ! Gán giá trị cho phần tử C theo hàng

Điều ý sử dụng lệnh DATA để gán giá trị cho phần tử mảng số giá trị gán (nằm hai dấu gạch chéo (/)) phải kích thước khai báo mảng Nếu có nhiều giá trị lặp lại liên tiếp ta sử dụng cách gán n*value, n số lần lặp lại liên tiếp, value giá trị lặp lại Trật tự xếp giá trị gán phải phù hợp với trật tự truy cập đến phần tử

mảng Chẳng hạn, câu lệnh sau đây:

DATA ((C(I,J), J= 1,3), I=1,3) /3*0,3*1, 3*2/

sẽ cho kết gán C(1,1) = C(1,2) = C(1,3) = 0; C(2,1) = C(2,2) = C(2,3) = 1; C(3,1) = C(3,2) = C(3,3) = Còn câu lệnh:

DATA C / 3*0, 3*1, 3*2 /

sẽ cho kết gán C(1,1) = C(2,1) = C(3,1) = 0; C(1,2) = C(2,2) = C(3,2) = 1; C(1,3) = C(2,3) = C(3,3) = Sở dĩ vì, câu lệnh thứ nhất, phần tửđược truy cập hàng, từ

hàng đến hàng 3, câu lệnh thứ hai, ta không cụ thể nên Fortran ngầm hiểu phần tử mảng truy cập theo cột, từ cột đến cột

5.3.2 Biểu thức mảng

Có thể thực phép toán biến mảng Trong trường hợp mảng phải có cấu trúc Ví dụ:

REAL, DIMENSION(10) :: X, Y

X + Y ! Cộng tương ứng phần tử X Y: X(I) + Y(I) X * Y ! Nhân tương ứng phần tử X Y: X(I) * Y(I) X * 3 ! Nhân tương ứng phần tử X với 3: X(I) * X * SQRT(Y) ! Nhân phần tử X với bậc ! phần tử tương ứng Y: X(I) * SQRT(Y(I)) X == Y ! Phép toán so sánh, cho kết quả.TRUE. ! X(I) == Y(I), .FALSE. ngược lại

5.3.3 Cấu trúc WHERE ELSEWHERE END WHERE

(106)

Hoặc

WHERE (Điu_kin) Các_câu_lệnh_1 ELSEWHERE Các_câu_lệnh_2 END WHERE

Tác động câu lệnh tìm phần tử mảng thỏa mãn Điu_kin, nếu Điu_kin được thỏa mãn thực Các_câu_lnh_1, ngược lại thực Các_câu_lnh_2 Điu_kin ởđây biểu thức lơgic Ví dụ:

REAL A (5)

A = (/ 89.5, 43.7, 126.4, 68.3, 137.7 /) WHERE (A > 100.0) A = 100.0

Trong đoạn chương trình trên, tất phần tử mảng A có giá trị > 100 sẽđược thay 100 Kết nhận được:

A = (89.5, 43.7, 100.0, 68.3, 100.0) Một ví dụ khác:

REAL A (5), B(5), C(5)

A = (/ 89.5, 43.7, 126.4, 68.3, 137.7 /) B = 0.0

C = 0.0

WHERE (A > 100.0) A = 100.0

B = 2.3 ELSEWHERE A = 50.0 C = -4.6 END WHERE

Ởđây, kết nhận

Mảng PT thứ PT thứ PT thứ PT thứ PT thứ

A 50.0 50.0 100.0 50.0 100.0 B 0.0 0.0 2.3 0.0 2.3

C −4.6 −4.6 0.0 −4.6 0.0

5.4 MẢNG ĐỘNG (DYNAMICAL ARRAY)

Mảng có kích thước cách xếp phần tử không xác định từ lúc khai báo gọi mảng động Các mảng động ln phải có thuộc tính ALLOCATABLE câu lệnh khai báo Trên ta gặp số ví dụ khai báo sử dụng mảng động Một cách tổng quát, có cách khai báo sau

Kiu_DL,DIMENSION(Mô_t),ALLOCATABLE :: Tên_biến

hoặc

(107)

hoặc

ALLOCATABLE [::] Tên_biến [(Mô_t)]

Trong Mơ_t mơ tả số chiều mảng, xác định dấu hai chấm (:), phân cách dấu phẩy Ví dụ:

REAL,DIMENSION(:),ALLOCATABLE :: X ! Mảng chiều REAL, ALLOCATABLE :: vector(:) ! Mảng chiều INTEGER,ALLOCATABLE :: matrix(:,:) ! Mảng chiều DIMENSION X (:,:) ! X mảng hai chiều REAL, ALLOCATABLE :: X ! X mảng động, thực ALLOCATABLE :: Y(:,:) ! Y mảng động chiều

Vì mảng động chưa xác định kích thước từđầu nên để sử dụng ta cần phải mơ tả

rõ kích thước cách xếp phần tử chúng trước truy cập

Câu lệnh ALLOCATE dùng đểđịnh vị kích thước cách xếp phần tử mảng

nhớ (tức cấp phát nhớ cho biến)

Câu lệnh DEALLOCATE dùng để giải phóng vùng nhớ mà biến mảng động cấp phát

Ví dụ 5.4 Xét đoạn chương trình

INTEGER, ALLOCATABLE :: matrix(:,:) REAL, ALLOCATABLE :: vector(:)

N = 123

ALLOCATE (matrix(3,5),vector(-2:N+2))

DEALLOCATE matrix, vector

Trong đoạn chương trình trên, vector matrix mảng động chiều hai chiều Sau câu lệnh ALLOCATE, matrix cấp phát vùng nhớ gồm hàng x cột x byte = 60 byte với cách đánh sốđịa phần tử mảng đến (hàng) đến (cột) Còn vector được cấp phát vùng nhớ gồm (N+2 − (−2) + 1) phần tử x byte = (123+2+2+1) x byte = 512 byte, với địa phần tử mảng đánh số từ−2 đến 125

Ví dụ 5.5 Cấp phát nhớ cho mảng tuỳ thuộc tham số xác định trình thực chương trình

REAL A, B(:,:), C(:), D(:, :, :) ALLOCATABLE C, D

READ (*, *) N, M

ALLOCATE (C(N), D(M, N, M))

(108)

Ví dụ 5.6 Sử dụng hàm ALLOCATEDđể xác định mảng cấp phát nhớ hay chưa REAL, ALLOCATABLE :: A(:)

IF (.NOT ALLOCATED(A)) ALLOCATE (A (5))

Trong ví dụ này, mảng A sẽđược cấp phát nhớ chưa cấp phát Ví dụ 5.7 Bẫy lỗi trình cấp phát nhớ cho mảng

REAL, ALLOCATABLE :: A(:) INTEGER ERR

ALLOCATE (A (5), STAT = ERR)

IF (ERR /= 0) PRINT *,“Khong cap phat duoc"

Ở đây, tham số STAT câu lệnh ALLOCATE trả giá trịERR (số nguyên) Nếu ERR=0 việc cấp phát nhớ thực thành công, ngược lại khơng cấp phát giá trị

của ERR mã lỗi lúc chạy chương trình

Ví dụ 5.8 Chương trình sau nhập mảng chiều X gồm số thực dương trước số phần tử mảng tối đa Do mảng X sẽđược cấp phát nhớ tăng dần nhập liệu Quá trình nhập liệu kết thúc số nhập vào số âm Thủ

thuật thực ởđây sử dụng mảng động, mảng để lưu số liệu trung gian REAL, DIMENSION(:), ALLOCATABLE :: X, OldX

REAL A INTEGER N

ALLOCATE (X(0)) ! Kích thước X (lúc đầu 0)

N = DO

Print*, ‘Cho mot so: ‘ READ(*,*) A

IF ( A < ) EXIT ! Nếu A<0

N = N + ! Tăng N lên đơn vị

ALLOCATE(OldX(SIZE(X))) ! Cấp phát kích thước của ! OldX kích thước X

OldX = X ! Lưu X vào OldX

DEALLOCATE( X ) ! Giải phóng X

ALLOCATE(X(N)) ! Cấp phát X có kích thước N

X = OldX ! Gán toàn OldX cho X

X(N) = A !Gán giá trị cho phần tử thứ N X

DEALLOCATE( OldX ) ! Giải phóng OldX

END DO

PRINT*,N, ( X(I), I = 1, N ) END

Hàm SIZE(X) chương trình để xác định kích thước mảng X 5.5 KIỂU CON TRỎ

(109)

POINTER [::] Tên_con_tr [(Mô_t)] [, ]

Kiu_DL, POINTER :: Tên_con_trỏ [(Mơ_t)]

Trong Tên_con_tr tên biến có kiểu trỏ; tên biến tên biến mảng cần phải khai báo Mơ_tmảng Ví dụ, khai báo biến trỏ sau

REAL A, X(:,:), B, Y(5, 5)

POINTER A, X ! A trỏ vô hướng, X trỏ mảng

REAL, POINTER :: A (:,:) REAL B, X(:,:)

POINTER B, X

Biến trỏ có thểđược cấp phát nhớ lệnh ALLOCATE hoặc trỏđến biến khác Biến trỏ trỏđến biến có thuộc tính đích (TARGET) biến xác

định Trong trường hợp biến trỏ trỏđến biến khác, xem “bí danh” biến mà trỏđến Để minh họa ta xét ví dụ sau

Ví dụ 5.9 Thao tác với biến trỏ INTEGER, POINTER :: P1 (:)

INTEGER, POINTER :: P2 (:)

INTEGER, ALLOCATABLE, TARGET :: D (:) ALLOCATE (D (7)) ! Cấp phát nhớ cho biến ĐICH D =

D (1:7:2) = 10 PRINT*, 'DICH=',D

P1 => D ! Con trỏ trỏ vào biến ĐICH PRINT*,'CON TRO P1=',P1

ALLOCATE (P1(10)) ! Cấp phát nhớ cho biến trỏ

P1 =

P2 => P1 ! Con trỏ trỏ vào biến xác định PRINT*,'CON TRO P1=',P1

print*

print*,'CON TRO P2=',P2 P2 =

PRINT*,'CON TRO P1=',P1 print*

print*,'CON TRO P2=',P2 END

(110)

5.5.1 Trạng thái trỏ

Tất biến trỏ chương trình ln tồn ba trạng thái sau:

− Trạng thái khơng xác định (undefined) Bắt đầu chương trình trỏđều trạng thái − Trạng thái không trỏ vào đâu (null), tức trỏ chưa phải “bí danh” biến − Trạng thái liên kết (associated), tức trỏ trỏ vào biến (đã “bí danh” biến “đích”)

Đểđưa trỏ trạng thái khơng trỏ vào đâu ta dùng câu lệnh: NULLIFY (P) ! P là biến trỏ

Để xác định trạng thái thời trỏ dùng hàm ASSOCIATED (P) ! P là biến trỏ

Hàm trả giá trị.TRUE. trỏ liên kết với biến, trả giá trị.FALSE. trỏở trạng thái không trỏ vào đâu

5.5.2 Cấp phát giải phóng biến trỏ

Biến trỏ có thểđược cấp phát nhớ câu lệnh ALLOCATE giải phóng câu lệnh DEALLOCATE tương tự mảng động Ví dụ:

REAL, POINTER :: P1

ALLOCATE (P1) ! Cấp phát nhớ cho P1 P1 = 17 ! Gán giá trị cho P1 nhưđối với biến PRINT*, P1

DEALLOCATE (P1) ! Giải phóng biến P1

Ta sử dụng tham sốSTAT cho hai câu lệnh ALLOCATE DEALLOCATE, chẳng hạn:

ALLOCATE( P1, STAT = ERR ) DEALLOCATE( P1, STAT = ERR )

Số nguyên ERR nhớđã cấp phát (hoặc giải phóng) xong

Ta sử dụng ALLOCATABLE POINTER để khai báo mảng động, chẳng hạn:

REAL, DIMENSION(:), POINTER :: X

INTEGER, DIMENSION(:,:), ALLOCATABLE :: A Để minh hoạ ta xét đoạn chương trình sau

REAL, POINTER :: A(:), B, C

REAL, ALLOCATABLE, TARGET :: D(:) REAL, TARGET :: E

REAL, ALLOCATABLE :: F(:, :)

(111)

A => D C => E

DEALLOCATE (B, D, F)

Nhưđã thấy, A mảng động có kiểu trỏ, C trỏđơn (vơ hướng), D mảng động có thuộc tính TARGET E biến “tĩnh” Khi A trỏđến D C trỏđến E

5.6 HÀM TRẢ VỀ NHIỀU GIÁ TRỊ

Trong mục 4.3 nhấn mạnh đến việc hàm trả giá trị gắn với tên hàm tên tham số tùy chọn RESULT Đó đặc tính thơng thường mà Fortran 77 phiên trước nhiều ngơn ngữ khác có Ngồi đặc tính đó, Fortran 90 cho phép định nghĩa hàm với khả trả nhiều giá trị Cú pháp định nghĩa loại hàm khơng có khác so với cách định nghĩa hàm thơng thường, ngồi trừ số khai báo định nghĩa chương trình gọi Ta xét ví dụ sau để minh họa

Giả sử có hàm f(x) = 3x2 + 2x − Hãy tính giá trị hàm giá trị đối số x1, x2, , xn Với cách định nghĩa thông thường, f(x) xác định thông qua hàm mà giá trị tính ứng với giá trị đối số x Và vậy, chương trình gọi, hàm sẽđược tham chiếu tới n lần ứng với n giá trị xi Thay cho cách làm này, ta xây dựng hàm mà đầu vào n giá trịđối số xi, đầu n giá trị hàm ứng với n giá trịđối sốđó Ta có chương trình sau

INTEGER, PARAMETER :: N = REAL, DIMENSION (N) :: X, FX DATA X /-3., -2., -1., 0., 1., 2., 3./ FX = F(X,N)

PRINT*, FX CONTAINS

FUNCTION F(X,N)

INTEGER, INTENT (IN) :: N

REAL, DIMENSION(N),INTENT(IN) :: X REAL, DIMENSION(SIZE(X)):: F

F(:) = 3*X(:)*X(:) + 2*X(:) - END FUNCTION

END

Trong chương trình trên, hàm F(X,N) hàm trong, có hai đối số hình thức mảng X số

nguyên N kích thước X Kết trả hàm mảng có kích thước kích thước X Nếu F(X,N)được khai báo hàm ngồi phần khai báo chương trình gọi cần phải có khối giao diện Chẳng hạn:

INTEGER, PARAMETER :: N = REAL, DIMENSION (N) :: X, FX INTERFACE

FUNCTION F(X,N)

INTEGER, INTENT (IN) :: N

(112)

END FUNCTION END INTERFACE

DATA X /-3., -2., -1., 0., 1., 2., 3./ !

FX = F(X,N) PRINT*, FX END

!

FUNCTION F(X,N)

INTEGER, INTENT (IN) :: N

REAL, DIMENSION(N),INTENT(IN) :: X REAL, DIMENSION(SIZE(X)):: F

F(:) = 3*X(:)*X(:) + 2*X(:) - END FUNCTION

BÀI TẬP CHƯƠNG

5.1 Ký hiệu X mảng chiều gồm 100 phần tử Viết chương trình: a) Gán 100 số nguyên dương cho phần tử tương ứng X, từ phần tử có số lớn đến phần tử có số

nhỏ nhất; b) Gán 50 số nguyên dương lẻđầu tiên cho 50 phần tửđầu tiên 50 số nguyên dương chẵn

đầu tiên cho 50 phần tử X; c) Gán 100 số tự nhiên chia hết cho cho phần tử X Mỗi trường hợp vậy, in kết lên hình thành 10 dòng, dòng 10 số cho thẳng hàng thẳng cột

5.2 Viết chương trình nhập vào dãy n số thực xếp chúng: a) theo thứ tự tăng dần; b) theo thứ tự giảm dần In kết lên hình thành ba cột với sốđược định dạng theo số thực dấu phẩy tĩnh có chữ số sau dấu chấm thập phân: cột dãy chưa xếp, cột dãy xếp theo thứ tự tăng dần, cột ba − giảm dần

5.3 Biết dãy n số thực biểu thị kết quan trắc biến ngẫu nhiên X có số giá trị khuyết thiếu mã hoá giá trị giả tạo −999.0 Viết chương trình thay giá trị giả

tạo giá trị trung bình số học giá trị lại In kết lên hình thành cột với sốđược định dạng theo số thực dấu phẩy tĩnh có chữ số sau dấu chấm thập phân: cột số liệu ban đầu, cột số liệu xử lý

5.4 Biết dãy số xi, i=1,2, n, chứa giá trị biểu thị kết quan trắc liên tục

trong n ngày của tượng xi nhận giá trị tượng xuất nhận giá trị

nếu tượng không xuất Ta gọi đợt tượng kéo dài m (ngày) có m phần tử liên tiếp dãy nhận giá trị phần tử trước sau m phần tử nhận giá trị Hãy lập bảng thống kê:

Số ngày kéo dài đợt (ngày)

1 M

(113)

5.5 Ký hiệu yi = f(xi) giá trị hàm f(x) giá trị x = xi Giả sử cho trước tập n cặp giá trị {(xi, yi), i=1, 2, , n}, đó giá trị y0 = f(x0) ứng với x0 cho trước có thểđược ước tính sử dụng cơng thức nội suy tuyến tính:

) (

) (

) (

1

0

i i

i i i

i x x

y y x x y y

− − −

+ =

+

+ , xi ≤ x0 ≤ xi+1 Viết chương trình nhập

vào n cặp số thực (xi, yi) một số thực x0 tính giá trị y0 tương ứng theo công thức (Chú ý xếp cặp số theo thứ tự tăng dần theo x trước tính tốn) Chương trình cho phép kiểm tra

điều kiện hợp lệ x0 sau:

Nếu Min{xi, i=1,2, ,n} ≤ x0 ≤ Max{xi, i=1,2, ,n} tính y0 in kết quả, ngược lại đưa thông báo “Giá trị x0 không hợp lệ”

5.6 Các phần tử ma trận tích hai ma trận xác định theo công thức: ∑

=

= n j

jk ij

ik a b

c

Viết chương trình nhập vào hai ma trận A(m,n) B(n,p) mà phần tử chúng số thực tính tích chúng In lên hình ma trận ban đầu ma trận kết cho thẳng hàng thẳng cột với thích hợp lý

5.7 Viết chương trình nhập vào giá trị phần tử ma trận số thực tính trung bình hàng, cột In kết lên hình dạng: cuối hàng trung bình hàng tương

ứng, cuối cột trung bình cột tương ứng, sốđược bố trí thẳng hàng thẳng cột với 5.8 Ký hiệu A mảng số nguyên gồm 20 phần tử Viết chương trình đọc vào giá trị

các phần tử mảng A, tìm in lên hình phần tử có giá trị lớn nhất, nhỏ vị trí tương

ứng chúng mảng (chỉ số mảng phần tử này)

5.9 Để thống kê tình hình tai nạn giao thơng năm, hàng tháng quan Công an phải thu thập số liệu từ N địa phương (tỉnh, thành phố) nước Giả sử số liệu thu thập lưu mảng nguyên A gồm N hàng (N địa phương) 12 cột (12 tháng năm) mà phần tử số vụ tai nạn xảy địa phương tháng Sau có số liệu, người ta chia số vụ

tai nạn thành khoảng giá trị, chẳng hạn 0−50, 51−100, 101−150, , >300, tiến hành tính số

trường hợp (tần số) có số vụ tai nạn xảy khoảng tương ứng cho tháng Ký hiệu B ma trận gồm M hàng (M khoảng giá trị số vụ tai nạn), 12 cột (12 tháng) chứa tần số tai nạn giao thông theo khoảng tháng năm Giả sử số liệu thu thập quan Công an lưu file DATA.TXT mà cấu trúc file là: Dòng chứa số nguyên dương N số địa phương có số liệu, N dịng tiếp theo, dịng gồm 12 cột lưu giá trị phần tử tương ứng mảng A Viết chương trình đọc số liệu từ file, tính ma trận tần số B in B lên hình thành M dịng, 12 cột

(114)

các phần tử mảng tương ứng Nhớ giá trị phần tử mảng, kể mảng chứa kết quả, số có chữ số

5.11 Số thứ tự ngày năm đánh số theo qui ước ngày 01 tháng 01 ngày thứ nhất, v.v., ngày 31 tháng 12 ngày thứ 365 (hoặc 366 năm nhuận) Viết chương trình nhập vào ngày, tháng, năm ngày tính xem thứ năm

5.12 Cũng với điều kiện tập 5.11 Viết chương trình nhập vào số thứ tự ngày năm năm xác định xem ngày, tháng

5.13 Viết chương trình nhập vào tọa độ N đỉnh đa giác lồi, phẳng xếp chúng theo thứ tự liên tiếp từđỉnh thứ đến đỉnh thứ N

5.13 Viết chương trình nhập vào tọa độ N đỉnh đa giác lồi, phẳng tọa độ

điểm M di động mặt phẳng xác định xem điểm M nằm hay nằm miền đa giác (nếu M nằm cạnh đa giác xem nằm miền đa giác Chương trình cho phép nhập tọa độđiểm M xác định vị trí với số lần hai tọa độ M

đều nhận giá trị−999.0 Gi ý: Có thể sử dụng thuật tốn tính tổng diện tích tam giác (khơng giao nhau) tạo điểm M với đỉnh đa giác so sánh diện tích với diện tích đa giác Chú ý so sánh hai số thực biểu thị hai giá trị diện tích

5.14 Giả sửđiểm thi học kỳ lớp sinh viên lưu file DIEM.TXT Cấu trúc file

được mô tả sau: Dòng tiêu đề ghi tên lớp, học kỳ, ; dòng gồm số nguyên dương số

lượng sinh viên (N) số mơn học (M); dịng gồm M số ngun dương số học trình M mơn học; N dịng tiếp theo, dòng gồm M+1 cột: cột ghi họ tên sinh viên, chiếm độ rộng 30 ký tự, kể từ ký tựđầu tiên dòng, M cột tiếp theo, ký tự thứ 31, M số thực, viết cách dấu cách, ghi kết thi M môn học tương ứng với sốđơn vị học trình dịng thứ Viết chương trình tính điểm trung bình chung học tập sinh viên theo công thức

TBCHT = ( ) ( )

( )

∑ ∑

= =

n i n i

x

1

i m«n trinh häc Sè

i môn trinh học Số i môn iểm Đ

, xếp loại học tập cho sinh viên (xem tập 2.14),

sắp xếp danh sách sinh viên theo thứ tự giảm dần điểm trung bình chung học tập, in kết vào file theo qui cách: Dòng đến dòng giống với file số liệu, từ dòng trởđi, dòng ghi họ

và tên sinh viên, điểm thi môn học, điểm trung bình chung học tập kết xếp loại học tập 5.15 Cho A ma trận M hàng, N cột gồm số nguyên Định nghĩa lân cận phần tử

ij

a phần tử A có số hàng số cột nhỏ lớn (nếu có) số i, j

đơn vị (tức i−1, i+1, j1, j+1) Viết chương trình lập ma trận B gồm M hàng, N cột mà phần tử B là: bij = số lận cận aij có giá trị lớn aij nhiều số lân cận aij có giá trị

(115)

5.16 Giả sử thông tin đặt chỗ vé máy bay cho chuyến bay hãng hàng không

(116)

CHƯƠNG BIẾN KÝ TỰ 6.1 KHAI BÁO BIẾN KÝ TỰ

Hiểu cách đơn giản, ký tự xâu (dãy) ký tự nằm cặp dấu nháy đơn (‘ ’) nháy kép (“ ”) Biến ký tự biến nhận giá trị ký tự Bởi ký tự

chiếm byte nhớ, nên dung lượng nhớ mà xâu ký tự chiếm phụ thuộc độ dài xâu ký tự Nói chung có nhiều cách khai báo biến ký tự nhưđã đề cập đến mục 1.4.2 Sau dẫn số ví dụ cách khai báo biến ký tự thường dùng

CHARACTER StrName [, ]

! Khai báo biến StrName có độ dài ký tự CHARACTER ([LEN=]n) StrName [, ] ! Khai báo biến StrName có độ dài n ký tự

CHARACTER *n StrName [, ] ! Tương tự CHARACTER StrName*n [, ] ! Tương tự

StrName tên biến ký tự, n số nguyên dương chỉđộ dài cực đại biến StrName Ví dụ:

CHARACTER ALPHA

!ALPHA xâu dài tối đa ký tự (nhận giá trị ‘A’, ) CHARACTER (25) Name

!Name xâu dài tối đa 25 ký tự

CHARACTER Word*5 ! Word xâu dài tối đa ký tự

Name = “Hanoi, Ngay “ Word = ‘Hanoi’

Khi biến ký tự có thuộc tính PARAMETER ta cịn khai báo xâu có độ dài chưa xác

định:

CHARACTER *(*) StrName

PARAMETER (StrName= “XauDai12KyTu”) Hoặc:

CHARACTER *(*) , PARAMETER :: ST1 = 'ABDCEF'

(117)

6.2 CÁC XÂU CON (SUBSTRING)

Xâu phận xâu ký tự Xâu có ký tự toàn

xâu Giả sửTEXT xâu có độ dài cực đại 80 ký tự: CHARACTER (80) TEXT

Khi TEXT(I:J) xâu gồm ký tự từ ký tự thứI đến ký tự thứJ xâu TEXT Từng ký tự riêng biệt xâu TEXT tham chiếu (truy cập) đến xâu TEXT(I:J) Ví dụ:

TEXT(J:J) ! ký tự thứ J xâu TEXT TEXT(:J) ! từ ký tự thứ đến ký tự thứ J TEXT(1:J) ! từ ký tự thứ đến ký tự thứ J TEXT(J:) ! từ ký tự thứ J đến ký tự thứ 80 TEXT(J:80) ! từ ký tự thứ J đến ký tự thứ 80 TEXT(:) ! từ ký tự thứ đến ký tự thứ 80 (cả xâu) TEXT(1:80) ! (hoặc TEXT) tương tự, xâu Nếu

TEXT = “Hanoi–Vietnam”

TEXT(3:5) có giá trị là “noi” TEXT(:5) có giá trị là “Hanoi” TEXT(7:) có giá trị là “Vietnam ”

TEXT(6:6) = “ * “ sẽ cho TEXT= “Hanoi * Vietnam” TEXT(2:5) = “ANOI” sẽ cho TEXT= “HANOI–Vietnam” 6.3 XỬ LÝ BIẾN KÝ TỰ

Xử lý biến ký tự Fortran vấn đề phức tạp Ở số ngôn ngữ lập trình khác (chảng hạn, PASCAL), việc xử lý biến ký tự nói chung hỗ trợ nhiều thủ tục hàm thư

viện Đối với Fortran, vấn đề thường phải người dùng tự lập Sau ta xét số tốn làm ví dụ minh hoạ

Ví dụ 6.1 Một thủ thuật xử lý biến ký tự chèn xâu vào xâu ký tự khác Có thể nêu nguyên tắc thực sau: Để chèn xâu SubStrvào vị trí xâu Str cho trước cần phải dịch chuyển ký tự phía sau vị trí cần chèn xâu Str sang phải số vị trí độ dài xâu SubStr.

Giả sử có xâu TEXT = “Hanoi Saigon”, muốn chèn xâu “− Hue” vào xâu để

nhận xâu “Hanoi – Hue – Saigon” ta lập trình sau: CHARACTER (50) TEXT

! 12345678901234 TEXT = 'Hanoi - Saigon' print*,TEXT

(118)

LENSub = ! Độ dài xâu cần chèn (“ – Hue”)

LenTEXT = LEN_TRIM( TEXT ) DO J = LenTEXT, I, -1

! Bắt đầu từ cuối xâu đến vị trí thứ I

TEXT( J+LENSub:J+LENSub ) = TEXT(J:J) ! Sao chép ký tự thứ J đến vị trí thứ J+LENSub

END DO

TEXT(I:I+LENSub) = ' - Hue' print*,TEXT

END

Hàm LEN_TRIM (TEXT) chương trình trả vềđộ dài xâu TEXT sau loại bỏ dấu cách bên phải của xâu Có thể mơ tả tác động chương trình sau Cho J nhận giá trị từđộ dài thực (LenTEXT) xâu TEXTđến vị trí cần chèn xâu (I), lần

vậy ta chép ký tự thứJ xâu TEXTđến vị trí J+LENSub Kết vòng lặp dịch chuyển (sao chép) nội dung TEXT(I:LenTEXT) lùi sang phải LENSub vị trí Tiếp ta ghi đè nội dung xâu ' Hue' vào xâu TEXT kể từ vị trí thứIđến vị trí thứI+LENSub

Ví dụ 6.2 Thay thế khoảng trống từ dấu cách (space bar) Giả sử ta định nghĩa từ dãy ký tự liên tiếp không chứa dấu cách Khi xâu có nhiều từ Khi gõ văn bản, hai từ chỉđược phép để dấu cách Hãy tìm khoảng trống từ

có nhiều dấu cách thay chúng dấu cách Ta có chương trình sau CHARACTER (Len=80) ST, ST1, ST2, ALLTRIM

INTEGER L LOGICAL OK

ST=' Ha noi la Thu cua VIET NAM ' PRINT*, ST

ST1 = ALLTRIM(ST) ! Cắt bỏ dấu cách hai đầu

OK = FALSE

DO WHILE (.NOT OK)

L = INDEX(TRIM(ST1),' ') ! Tìm vị trí có dấu cách

IF (L > 0) THEN ! Nếu tìm thấy:

OK = FALSE

ST2 = ' ' !Gán dấu cách cho ST2

ST2(1:L-1) = ST1(1:L-1)! Sao chép nội dung ST1

ST2(L:) = ST1(L+1:) ! vào ST2 sau loại

! bỏ bớt dấu cách

ST1 = ST2 ! Sao chép ST2 vào ST1

ELSE

OK = TRUE ! Nếu khơng tìm thấy

END IF END DO ST = ‘ ‘ ST = ST1 PRINT*,ST END

(119)

CHARACTER *80 ST, ALLTRIM INTEGER I, J

J=LEN_TRIM(ST) I=0

DO I=I+1

IF (ST(I:I) /= ' ') EXIT ENDDO

ALLTRIM = ST(I:J) RETURN

END

Trong chương trình ta xây dựng hàm ALLTRIM có chức loại bỏ tất ký tự trống bên phải bên trái xâu ký tự Còn INDEX TRIM hàm thư

viện Fortran Hàm INDEX trả vị trí lần gặp xâu xâu ký tự; hàm TRIM trả xâu ký tựđã cắt bỏ ký tự trống bên phải xâu ký tự

Ví dụ 6.3 Tìm tách từ xâu Giả sử có xâu ký tựST Hãy xác định xem xâu có từ cho biết nội dung chúng

CHARACTER (Len=80) ST, ST1, ST2, ALLTRIM CHARACTER*10 S(20) ! Mảng chứa nội dung từ

INTEGER L, I, K LOGICAL OK

ST=' Ha noi la Thu cua VIET NAM ' PRINT*, ST

CALL NO_DOUBLE_SPACES(ST) ST1 = ST

I=0 ! Biến đếm số từ có xâu

L=1 ! Vị trí từ xâu

OK=.FALSE

DO WHILE (.NOT.OK)

K=INDEX( TRIM(ST1(L:)), ' ')

IF (K > 0) THEN ! Nếu tìm thấy dấu cách từ

I=I+1

S(I)=ST1(L:L+K-1) ! Lưu nội dung từ thứ I

L=L+K ELSE

OK=.TRUE END IF END DO I = I +

S(I)=ST1(L:LEN_TRIM(ST1)) PRINT*,’ So tu xau = ‘, I

PRINT*,’ Noi dung cac tu xau la ‘ DO L=1,I

(120)

SUBROUTINE NO_DOUBLE_SPACES(ST) CHARACTER*80 ST,ST1,ST2, ALLTRIM INTEGER L

LOGICAL OK ST1=ALLTRIM(ST) OK = FALSE

DO WHILE (.NOT OK) L = INDEX(TRIM(ST1),' ') IF (L > 0) THEN

OK = FALSE ST2 = ' '

ST2(1:L-1) = ST1(1:L-1) ST2(L:) = ST1(L+1:) ST1 = ST2

ELSE

OK = TRUE END IF

END DO ST=' ' ST=ST1 RETURN END

Thủ tục NO_DOUBLE_SPACES thực chất nội dung ví dụ 6.2 đây, ta xây dựng thành chương trình để tiện sử dụng Thủ tục tham chiếu tới hàm ALLTRIMđã đề cập đến ví dụ 6.2

Ví dụ 6.4 Cho một xâu chứa họ tên đầy đủ người Hãy cho biết rõ họ, tên tên đệm (họđệm) người

Để giải toán ta giả thiết rằng, họ người từđầu tiên xâu, tên người từ cuối xâu, phần lại xâu nằm họ tên tên đệm Ta viết chương trình sau

CHARACTER (Len=80) ST, ST1

CHARACTER *80 FIRST_WORD, END_WORD, ALLTRIM CHARACTER *80 HO, DEM, TEN, ST2

ST=' Nguyen Le Hoang Viet ' CALL NO_DOUBLE_SPACES(ST) ! Cắt bỏ khoảng trống thừa

ST1=ST

HO = FIRST_WORD (ST1) ! Họ từđầu tiên

TEN = END_WORD (ST1) ! Tên từ cuối

L1 = LEN_TRIM (HO) L2 = LEN_TRIM(TEN) L3 = LEN_TRIM(ST1) ST2 = ST1(L1+1:L3-L2)

(121)

print*,HO print*,DEM print*,TEN END

!!!!!!!!!!!!!!!!!!!!!!!!

FUNCTION FIRST_WORD (ST) CHARACTER*80 ST, FIRST_WORD I=0

DO I=I+1

IF (ST(I:I) == ' ') EXIT ENDDO

FIRST_WORD = ST(:I-1) RETURN

END

FUNCTION END_WORD (ST) CHARACTER*80 ST, END_WORD K =

J = LEN(TRIM(ST)) DO

K = K + J = J -

IF (ST(J:J) == ' ') EXIT ENDDO

J = LEN_TRIM(ST)

END_WORD = ST(J-K+1:J) RETURN

END

Các hàm FIRST_WORD END_WORD chương trình tương ứng trả từđầu tiên cuối xâu

Một số hàm xử lý xâu ký tự thư viện Fortran LEN (Str): trả vềđộ dài cực đại (khai báo) xâu Str

LEN_TRIM (Str): trả độ dài xâu Str sau loại bỏ ký tự trống (dấu cách) bên phải

ACHAR (I): trả ký tự thứI bảng mã ASCII IACHAR(c): trả số thứ tự bảng mã ASCII ký tự c

INDEX (Str, SubStr [, back]): trả vị trí xâu SubStr xâu Str Tham số

tùy chọn back có ý nghĩa sau:

(122)

REPEAT (Str, ncopies): trả xâu gồm ncopies lần chép Str TRIM (Str): trả xâu Str sau cắt bỏ ký tự trống bên phải 6.4 PHÉP TOÁN GỘP XÂU KÝ TỰ

Phép toán gộp hai xâu ký tựđược ký hiệu // Giả sử ta muốn tạo tên file từ hai xâu Name chứa tên Ext chứa phần mở rộng Có thể hai xâu cịn chứa dấu cách ởđầu cuối xâu Trước gộp hai xâu thành xâu có ý nghĩa tên file ta cần phải cắt bỏ dấu cách Việc cắt bỏ thực lời gọi hàm ALLTRIM ví dụ mục 6.3

Để bạn đọc nắm bắt tình khác xử lý biến ký tự, chương trình sau

đây sẽđưa phương án khác Ví dụ 6.5 Tạo tên file từ hai xâu CHARACTER (80) FName, Name, Ext ! 123456789012345

Name = ' gl04012200 ' Ext = ' dat '

! Cả xâu có chứa dấu cách ởđầu cuối Len1 = INDEX(TRIM(Name),' ',.true.)

Len2 = INDEX(TRIM(Ext),' ',.true.)

! Xác định vị trí dấu cách cuối bên trái ! hai xâu (Kết quả: Len1=3, Len2=2) Len1 = Len1 +

Len2 = Len2 +

! Ký tự sau dấu cách Len3 = LEN(TRIM(Name)) Len4 = LEN(TRIM(Ext))

! Xác định độ dài xâu sau cắt bỏ dấu cách ! bên phải hai xâu (Kết quả: Len3=13, Len4=8) FName = Name(Len1:Len3) // Ext(Len2:Len4) ! Gộp tên phần mở rộng để tạo thành tên file PRINT*, FName

END

Khi chạy chương trình này, ta nhận kết hình “gl04012200.dat6.5 TẠO ĐỊNH DẠNG FORMAT BẰNG XÂU KÝ TỰ

Biểu thức xâu ký tự sử dụng để tạo định dạng FORMAT tựđộng chương trình Ví dụ sau cho phép in số thực dạng dấu phẩy tĩnh với độ rộng trường 9, số

chữ số thập phân cần in lựa chọn tùy ý (tối đa chữ số): CHARACTER (1), DIMENSION(0:4) :: TP = &

& (/'0','1','2','3','4'/) ! 123456

CHARACTER (8) :: FMT = "(F9.?)" PRINT*,'Cho so X:'

READ*,X

(123)

READ*, N

FMT(5:5)=TP(N) ! Thay dấu (?) số chữ số thập phân PRINT FMT, X

END

Chương trình sau in N số nguyên dương dòng, số chiếm vị trí (độ rộng trường 4):

! 1234567890

CHARACTER *11 :: FMT = '(2X, ???I4)' CHARACTER *3 SubSt

PRINT*,'CHO SO N:' READ*,N

WRITE(SubSt,'(I3.3)') N ! Đổi số N thành ký tự

FMT(6:8)=SubSt

WRITE(*, FMT) (I,I=1,N) END

Sau ví dụ kết xuất thơng tin dạng mảng file TEXT có qui cách Giả sử thực chương trình ta muốn in mảng hai chiều file TEXT dạng ma trận, tức liệu lưu trữ file phải bố trí thẳng hàng thẳng cột, kích thước mảng khơng biết trước mà chỉđược xác định q trình tính tốn Để làm điều ta sử dụng đoạn chương trình sau

PROGRAM In_Co_Dinh_Dang REAL, ALLOCATABLE :: A(:,:) INTEGER M, N, I, J

CHARACTER FMT*80

M = N =

ALLOCATE (A(N, M))

OPEN (3, FILE=”OUT.TXT”)

WRITE (FMT,'(A1,I2.2,A6)') '(', M, 'F15.8)' DO I=1,N

WRITE (3,FMT) (A(I,J),J=1,M)

ENDDO

END

6.6 MẢNG XÂU KÝ TỰ

Xâu ký tự khai báo dạng biến đơn khai báo dạng biến mảng Mảng xâu ký tự mảng phần tử xâu ký tự Các phần tử mảng xâu ký tự phải có độ dài giống Như vậy, phần tử mảng có độ dài n ký tự, mảng chiều gồm m phần tử có kích thước n x m ký tự Ví dụ, chương trình sau định nghĩa ngày tuần xâu ký tựđươc xác định phần tử tương ứng mảng:

(124)

& ‘Thu 6’,’Thu 7’,’Chu nhat’ /) PRINT*,’Cac tuan la:’ DO I = 1,7

PRINT*, DayOfWeek (I) END DO

END

Trong ví dụ này, mảng DayOfWeek mảng chiều gồm phần tử, phần tử xâu có độ dài cực đại ký tự

Ta truy cập đến ký tự riêng biệt phần tử mảng Ví dụ, DayOfWeek(1)(5:5) ký tự thứ phần tử thứ mảng, nên có giá trị “2

Bằng cách tương tự, ta có thểđịnh nghĩa mảng ký tự hai chiều, ba chiều,… BÀI TẬP CHƯƠNG

6.1 Một từđược định nghĩa dãy ký tự khác dấu cách đứng liền Giả thiết từ chỉđược phân cách dấu cách Viết chương trình nhập vào xâu ký tự có độ dài tùy ý cho biết xâu có từ, từ dài ký tự

6.2 Định nghĩa câu dãy từ kết thúc dấu chấm (.) Viết chương trình nhập vào xâu ký tự cho biết xâu có câu

6.3 Theo qui định gõ văn bản, dấu phân cách chấm câu, dấu phẩy, dấu ngoặc mở, dấu ngoặc đóng, dấu chấm than, dấu hỏi,… phải viết liền sau ký tự kết thúc từ Giả sử

có file văn (TEXT file) có tên DOC.TXT mà nội dung gồm N dịng, dịng dài khơng q 80 ký tự Viết chương trình đọc file văn cho biết file có lỗi xảy gõ dấu chấm câu dấu phẩy không qui định

6.4 Phát triển tập 6.3 cho trường hợp dấu phân cách khác sửa lỗi cho file văn

6.5 Viết chương trình đọc vào câu (kết thúc dấu chấm) in lên hình (khơng in dấu chấm) theo thứ tự nghịch đảo: a) từ; b) ký tự Ví dụ, “Ha Noi.” Ỵ “Noi Ha” “ioN aH”

6.6 Công thức đồng dư Zeller có thểđược dùng để tính ngày tuần có dạng:

[ ] [ ] [ ]

( m k y y c c)

f = 2.6 −0.2 + + + /4 + /4 −2 modulo

Trong m số thứ tự tháng, với qui ước tháng tháng tương ứng tháng thứ 11 tháng thứ

12 năm trước, tháng tháng thứ 1,…, tháng 12 tháng thứ 10; k số thứ tự ngày tháng; c số thứ tự kỷ; y số thứ tự năm kỷ; f=0 Chủ Nhật, f=1 Thứ Hai,…; dấu ngoặc vuông ký hiệu lấy phần nguyên Ví dụ, ngày 23 tháng năm 1963 biểu diễn m = 6, k = 23, c = 19, y = 63; ngày 01 tháng 01 năm 1980 biểu diễn m = 11, k = 1, c = 17, y = 99 Viết chương trình đọc xâu ký tự mơ tả thời gian ngày đó, chẳng hạn, “Today is 08/03/2005”, chuyển thông tin ngày, tháng, năm từ xâu ký tự thành dạng số sử dụng công thức Zeller để xác định thứ tuần

(125)

6.8 Theo qui ước ghi số liệu quan trắc mưa, có mưa khơng tiến hành đo lượng mưa ghi dấu (x), nghĩa số liệu, không mưa ghi dấu (−), trường hợp khác lượng mưa biểu thị số thực không âm Giả sử file số liệu RAIN.TXT lưu giá trị quan trắc tổng lượng mưa ngày 10 năm, năm 12 tháng, trạm đó, dòng gồm tối đa 31 số, cách dấu cách, ghi số liệu ngày tháng Viết chương trình đọc file số liệu cho biết có ngày có mưa khơng quan trắc, ngày không mưa

(126)

CHƯƠNG KIỂU FILE 7.1 KHÁI NIỆM

Trong hệ thống vào/ra Fortran, liệu lưu trữ chuyển đổi chủ yếu thông qua file Tất nguồn vào/ra cung cấp kết xuất liệu xem các file Các thiết bị hình, bàn phím, máy in xem file ngoài (external files), kể file số liệu lưu trữ

đĩa Các biến nhớ đóng vai trị file, đặc biệt chúng sử dụng để

chuyển đổi từ dạng biểu diễn mã ASCII sang số nhị phân (binary) Khi biến sử dụng theo cách này, chúng gọi file trong

Các file trong file ngoài liên kết với gọi thiết bị lôgic Thiết bị lôgic khái niệm sử dụng để tham chiếu đến file Ta nhận biết thiết bị lơgic liên kết với file định danh (UNIT=)

Định danh UNIT file tên biến ký tự liên kết với Định danh UNITđối với file số nguyên dương gán lệnh OPEN, hoặc số kết nối trước định danh UNITđối với thiết bị, dấu (*) Các định danh UNIT

được kết nối với thiết bị định khơng mở (OPEN) Các UNIT ngồi kết nối bị ngắt kết nối kết thúc thực chương trình UNIT bịđóng lệnh CLOSE

Tại thời điểm UNIT kết nối với nhiều file, file không kết nối với nhiều thiết bị

Định danh UNIT liên kết với file phải số nguyên, biểu thức nguyên dấu (*) Nếu số nguyên biểu thức nguyên, giá trị liên kết với file đĩa; dấu (*) đọc vào hiểu bàn phím, cịn in ngầm định hình Ví dụ:

OPEN (UNIT = 10, FILE = ‘TEST.dat')

WRITE(10,'(A18,\)')' Ghi vao File TEST.dat & & da lien ket voi UNIT 10‘

WRITE (*, '(1X, A30,\)') ' In man hinh.‘

Fortran ngầm định số thiết bị chuẩn liên kết với định danh UNIT sau:

− Dấu (*): Màn hình bàn phím

UNIT = 0: Màn hình bàn phím

UNIT = 5: Bàn phím

(127)

Ví dụ 7.1 Trong chương trình sau đây, UNIT khơng liên kết với file ngồi sẽđược hiểu hình Tuy nhiên muốn liên kết với file ngồi ta phải sử dụng lệnh mở file (OPEN), để loại bỏ liên kết ta dùng lệnh đóng file (CLOSE)

REAL a, b

! In hình (UNIT đã kết nối trước). WRITE(6, '('' Day la UNIT 6'')')

! Sử dụng lệnh OPEN để kết nối UNIT 6 ! với file ngồi có tên 'COSINES'.

OPEN (UNIT = 6, FILE = 'COSINES', STATUS = 'NEW') DO a = 0.1, 6.3, 0.1

b = COS (a)

! Ghi vào file 'COSINES'. WRITE (6, 100) a, b 100 FORMAT (F3.1, F5.2) END DO

! Đóng file, cắt bỏ kết nối với file đĩa. CLOSE (6)

! Kết nối lại UNIT với hình cách ! ghi hình

WRITE(6,' ('' Ket thuc chuong trinh '')') END

Định danh UNIT liên kết với file xâu ký tự mảng ký tự Đối với file ta sử dụng câu lệnh READ WRITE Ta mở đóng file nhưđối với file ngồi

Có thểđọc ghi file với việc sử dụng lệnh định dạng FORMAT nhưđối với file Trước câu lệnh vào/ra thực hiện, file định vị vị trí đầu ghi

đầu tiên

Bằng khái niệm file trong, Fortran cho phép ta chuyển đổi dạng liệu, chẳng hạn đổi ký tự sang số đổi số sang dạng ký tự

Ví dụ 7.2 Chuyển đổi liệu từ ký tự thành số từ số thành ký tự sử dụng khái niệm file

CHARACTER(10) str INTEGER n1, n2, n3 CHARACTER(14) fname INTEGER I

str = " 3" ! Xâu ký tự

READ(str, *) n1, n2, n3

! Đọc n1, n2, n3 từ xâu str (Chuyển ký tự thành số)

PRINT*,n1,n2,n3 I =

WRITE (fname, 200) I

! Ghi giá trị I vào fname (Chuyển số thành ký tự)

(128)

PRINT*,fname END

Trong chương trình trên, Str Fname file Kết chạy chương trình ta nhận

được n1=1, n2=2, n3=3, fname = “FM004.DAT” 7.2 PHÂN LOẠI FILE

Fortran hỗ trợ hai phương pháp truy cập file truy cập truy cập trực tiếp, ba dạng cấu trúc file có định dạng (Formatted), không định dạng (Unformatted), dạng nhị phân (Binary)

7.2.1 File có định dạng (Formatted Files)

Có thể tạo file có định dạng lệnh OPEN với tùy chọn FORM = FORMATTED”, bỏ qua tham sốFORM file mởở chếđộ truy cập Các ghi file có định dạng

được lưu trữ ký tự ASCII Bởi ta nói file có định dạng ASCII file, hay TEXT file Mỗi ghi kết thúc ký tự (ASCII) điều khiển RETURN (CR) xuống dòng (LF

line feed).Để xem nội dung file sử dụng trình soạn thảo văn thơng thường Ví dụ 7.3 Tạo file có định dạng (TEXT file)

OPEN (UNIT=3, FILE= “TEST.TXT”, FORM= “FORMATTED”) WRITE (3, *) “Day la file co dinh dang”

CLOSE (3) END

7.2.2 File không định dạng (Unformatted Files)

Để tạo file khơng định dạng sử dụng lệnh OPEN với tùy chọn FORM=UNFORMATTED”, bỏ qua tham sốFORM file mởở chếđộ truy cập trực tiếp File không định dạng chuỗi ghi khối vật lý Mỗi ghi chứa giá trị

lưu trữ gần giống với sử dụng nhớ chương trình Tốc độ truy cập liệu file nhanh chúng tổ chức chặt chẽ file có định dạng Nếu file không định dạng lưu trữ số, chúng khơng thểđọc trình soạn thảo văn thơng thường Nói xác hơn, sử dụng trình soạn thảo đểđọc file khơng định dạng, thông tin số xem cách rõ ràng

Ví dụ 7.4 Tạo file không định dạng đọc thông tin từ file không định dạng CHARACTER *50 St

INTEGER A,B,C,D

OPEN (UNIT=3, FILE= "TEST.TXT", FORM= "UNFORMATTED") St="Day la file khong dinh dang truy cap tuan tu"

WRITE (3) St ! Bản ghi thứ

WRITE (3) 1,2,3,4 ! Bản ghi thứ

WRITE (3) 5,6,7,8 ! Bản ghi thứ ba

REWIND (3) ! Quay vị trí ghi thứ

READ (3) St ! Đọc ghi thứ

(129)

READ (3) A, B, C, D ! Đọc ghi thứ

PRINT*, A, B, C, D

READ (3) A, B, C, D ! Đọc ghi thứ

PRINT*, A, B, C, D CLOSE (3)

END

Trong ví dụ trên, câu lệnh REWIND(3) có tác dụng đưa trỏ file định vịở vị trí đầu file 7.2.3 File dạng nhị phân (Binary Files)

Có thể tạo file nhị phân lệnh OPEN với tùy chọn FORM= 'BINARY' File nhị phân dạng file chặt chẽ nhất, tốt cho việc lưu trữ số liệu có dung lượng lớn

Ví dụ 7.5 Đọc ghi file nhị phân truy cập CHARACTER *50 St

INTEGER A,B,C,D

OPEN (UNIT=3, FILE= "TEST.TXT", FORM= "BINARY") St= "Day la file dang nhi phan truy cap tuan tu"

WRITE (3) St ! Bản ghi thứ

WRITE (3) 1,2,3,4 ! Bản ghi thứ hai

REWIND (3) ! Quay lại đầu ghi thứ

READ (3) St ! Đọc ghi thứ

PRINT*,ST

READ (3) A, B, C, D ! Đọc ghi thứ hai

PRINT*, A, B, C, D CLOSE (3)

END

Về hình thức, nói chung khơng có khác nhiều cách tạo file truy cập file file không định dạng file nhị phân Sự khác hai loại file tổ chức liệu file Ta xét đến vấn đề mục

7.2.4 File truy cập (Sequential-Access Files)

Dữ liệu file cần phải truy cập hợp lệ, ghi tiếp nối sau ghi khác, trừ ta thay đổi vị trí trỏ file câu lệnh REWIND BACKSPACE Các phương pháp vào/ra sử dụng file truy cập NONADVANCING, LISTDIRECTED, NAMELISTDIRECTED Các file cần phải file Đối với file liên kết với thiết bị cần phải sử dụng cách truy cập Các thiết bị thiết bị lưu trữ vật lý Bàn phím, hình máy in thiết bị

7.2.5 File truy cập trực tiếp (Direct-Access Files)

Dữ liệu file truy cập trực tiếp có thểđược đọc ghi theo trình tự Các ghi

(130)

7.3 TỔ CHỨC DỮ LIỆU TRONG FILE

Nhưđã thấy trên, với hai phương pháp truy cập file ba dạng cấu trúc file, cách tương

đối ta phân chia thành sáu dạng tổ chức liệu file: 1) File truy cập có định dạng (Formatted Sequential) 2) File truy cập trực tiếp có định dạng (Formatted Direct)

3) File truy cập không định dạng (Unformatted Sequential) 4) File truy cập trực tiếp không định dạng (Unformatted Direct) 5) File truy cập dạng nhị phân (Binary Sequential) 6) File truy cập trực tiếp dạng nhị phân (Binary Direct) 7.3.1 File truy cập có định dạng

File có định dạng chuỗi ghi có định dạng ghi cách (hình 7.1) đọc theo thứ tự xuất file Các ghi có độ dài biến đổi rỗng

Chúng phân cách ký tự điều khiển

RETURN ($0D hay #13) ký tự xuống dòng ($0A hay

#10)

Ví dụ 7.6 Tạo file truy cập có định dạng OPEN (3, FILE='TEST1.TXT')

! TEST1.TXT ngầm định file có định dạng

WRITE (3, '(A, I3)') 'RECORD',

! Kết ghi là: RECORD001 (9 ký tự=9 byte) WRITE (3, '()') ! Bản ghi trống (0 byte)

WRITE (3, '(A11)') 'The 3rd One' ! 11 ký tự

CLOSE (3) END

Như vậy, bỏ qua tuỳ chọn FORM= ACCESS= câu lệnh OPEN file sẽđược ngầm hiểu file có định dạng Mơ tả cấu trúc liệu file TEST1.TXTđược cho hình 7.2 Vì ghi phân cách ký tựđiều khiển nên ghi có

độ dài khác tùy ý Nếu sử dụng trình soạn thảo để xem nội dung file ta thấy file có dịng, dịng thứ hai dòng trống:

RECORD The 3rd One

Hình 7.1 Cấu trúc file tuần tự

(131)

Hình 7.2 Cấu trúc file TEST1.TXT

7.3.2 File truy cập trực tiếp có định dạng

Trong file truy cập trực tiếp có định dạng, tất ghi có độ dài có thểđược ghi đọc theo thứ tự Kích thước ghi tùy chọn RECL= câu lệnh OPEN nên lớn số byte ghi dài Các ký tựRETURN (CR) xuống dòng (LF) ký tự phân cách ghi khơng tính vào giá trị RECL Một ghi truy cập trực tiếp ghi, khơng thể bị xóa bị ghi đè

Khi kết xuất (output) file truy cập trực tiếp có định dạng, số liệu khơng lấp đầy hồn tồn ghi, trình biên dịch đệm vào phần lại ghi dấu cách (BLANK SPACES) Các dấu cách bảo đảm file chứa ghi lấp đầy hoàn toàn tất ghi có độ dài

Khi đọc vào (input), trình biên dịch ngầm định có đệm dấu cách vào danh sách

đọc vào định dạng đòi hỏi nhiều liệu ghi chứa Có thể bỏ qua ngầm định việc đệm vào dấu cách liệu vào cách đặt tùy chọn PAD= “NO” câu lệnh OPEN Khi đặt PAD= NO”, ghi đọc vào cần phải chứa lượng liệu danh sách đầu vào định dạng FORMAT, không xuất lỗi PAD= “NO” ảnh hưởng kết xuất

Ví dụ 7.7 Đọc ghi file truy cập trực tiếp có định dạng character st*10

integer n

OPEN (3,FILE='TEST2.TXT',FORM='FORMATTED',& ACCESS='DIRECT',RECL=10)

st = 'RECORD ONE'

WRITE (3, '(A10)', REC=1) st ! Bản ghi thứ

n= 30303

WRITE (3, '(I5)', REC=3) n ! Bản ghi thứ ba

CLOSE (3)

OPEN (3,FILE='TEST2.TXT', FORM='FORMATTED', & ACCESS='DIRECT',RECL=10)

st = ' ' n=0

read(3,'(A10)',rec=1) st ! Đọc ghi thứ

read(3,'(I5)', rec=3) n ! Đọc ghi thứ ba

(132)

print*,n END

Qua thấy rằng, để làm việc với file truy cập trực tiếp có định dạng, câu lệnh OPEN phải chứa tham số tuỳ chọn FORM = 'FORMATTED', ACCESS = 'DIRECT' RECL =

Độ_dài_bn_ghi Mô tả tổ chức liệu theo chương trình ví dụ 7.7 cho hình 7.3 Độ dài ghi 10 byte, cộng với với byte chứa ký tựđiều khiển, nên vị trí ghi chưa có liệu có “khoảng trống” 12 byte khơng xác định Đối với ghi có liệu chiếm 10 byte, số byte cịn lại sẽđược lấp đầy (đệm) dấu cách

Hình 7.3 Cấu trúc file TEST2.TXT

7.3.3 File truy cập không định dạng

File không định dạng tổ chức khác dòng máy khác trình biên dịch Fortran khác Sau ta xét đến loại file trình biên dịch Microsoft Fortran PowerStation

Các ghi file khơng định dạng có độ dài biến đổi File không

định dạng tổ chức thành khúc 130 byte nhỏ hơn, gọi khối vật lý Mỗi khối vật lý bao gồm liệu gửi vào file (cho đến 128 byte) byte chỉđộ dài trình biên dịch chèn vào Các byte độ dài cho biết ghi bắt đầu kết thúc ởđâu Mỗi ghi lôgic tham chiếu đến ghi không định dạng chứa nhiều khối vật lý Các ghi lơgic lớn tùy ý; trình biên dịch biết cung cấp số khối vật lý cần thiết để chứa

Khi tạo ghi lơgic gồm nhiều khối vật lý, trình biên dịch đặt byte độ dài 129 để số liệu khối vật lý nối tiếp vào khối vật lý Ví dụ, ghi lơgic có độ dài 140 byte sẽđược tổ chức hình 7.4

Ví dụ 7.8 Chương trình sau tạo file không định dạng Cấu trúc liệu file mơ tả hình 7.5

CHARACTER xyz(3) INTEGER(4) idata(35)

DATA idata /35 * -1/, xyz /'x', 'y', 'z'/

OPEN (3, FILE='TEST3.TXT',FORM='UNFORMATTED') WRITE (3) idata

(133)

CLOSE (3) END

Ta thấy file liệu tạo gồm hai ghi lôgic Bản ghi thứ chứa liệu mảng idata gồm 35 x = 140 byte Bản ghi thứ hai chứa liệu mảng xyz, chiếm 3 byte Vì ghi thứ

nhất có độ dài lớn 128 byte, nên lưu trữ hai khối vật lý Khối thứ nhất: từ byte thứ

đến byte thứ 131, với 128 byte liệu byte chỉđộ dài đặt 129, hàm nghĩa liệu ghi chứa tiếp khối Khối thứ hai: từ byte thứ 132 đến byte thứ

145, gồm 12 byte liệu byte độ dài đặt 12 Bản ghi thứ hai gồm byte nên

được chứa trọn vẹn khối vật lý

Hình 7.4 Cấu trúc file không định dạng

Hình 7.5 Cấu trúc file TEST3.TXT

7.3.4 File truy cập trực tiếp không định dạng

File truy cập trực tiếp không định dạng chuỗi ghi khơng định dạng; ghi đọc ghi theo thứ tự tùy ý Tất ghi có độ dài cho tham số RECL= câu lệnh OPEN Giữa ghi khơng có byte phân định ranh giới, hay nói cách khác, file truy cập trực tiếp khơng định dạng không chứa thông tin cấu trúc ghi Có thể

ghi phần ghi vào file truy cập trực tiếp khơng định dạng Trình biên dịch Fortran sẽđệm vào ghi ký tự rỗng (NULL) ASCIIđể cho độ dài ghi cố định Những ghi file khơng ghi chứa số liệu không xác định

Ví dụ 7.9 Chương trình sau tạo file truy cập trực tiếp không định dạng chứa hai ghi liệu ghi vào ghi thứ thứ ba Bản ghi thứ hai không chứa liệu Mô tả cấu trúc liệu file cho hình 7.6

OPEN (3, FILE='TEST4.TXT', RECL=10, &

FORM = 'UNFORMATTED', ACCESS = 'DIRECT') WRITE (3, REC=3) TRUE., 'abcdef'

WRITE (3, REC=1) 2049 CLOSE (3)

(134)

Hình 7.6 Cấu trúc file TEST4.TXT

7.3.5 File truy cập dạng nhị phân

File truy cập dạng nhị phân chuỗi giá trịđược ghi đọc theo trình tự

và lưu trữ số nhị phân Trong file dạng nhị phân không tồn ranh giới ghi, khơng có byte đặc biệt để cấu trúc file Số liệu đọc ghi không bị thay đổi dạng độ dài Đối với hạng mục vào/ra, byte nhớ byte file

Ví dụ 7.10 Chương trình sau tạo file truy cập dạng nhị phân gồm ba ghi có

độ dài khác Cấu trúc liệu file mô tả hình 7.7 INTEGER(1) Chuong(4)

CHARACTER(4) V1(3) CHARACTER(4) V2 DATA Chuong /4*7/

DATA V2 /' is '/, V1 /'What',' you',' see'/

OPEN (3, FILE='TEST5.TXT',FORM='BINARY') WRITE (3) V1, V2

WRITE (3) 'what ', 'you get!' WRITE (3) Chuong

CLOSE (3) END

Hình 7.7 Cấu trúc file TEST5.TXT

7.3.6 File truy cập trực tiếp dạng nhị phân

(135)

RECL= câu lệnh OPEN Có thể ghi phần ghi vào file trực tiếp dạng nhị phân; phần chưa sử dụng ghi chứa liệu không xác định

Một câu lệnh đơn READ WRITE truyền tải liệu nhiều ghi liên tiếp file Tuy nhiên điều gây nên lỗi

Ví dụ 7.11 Chương trình sau tạo file truy cập trực tiếp dạng nhị phân gồm ghi Sau đọc thơng tin từ file theo trình tự qui cách khác với cách tạo file Bạn đọc cần nghiên cứu phân tích lời chương trình cách kỹ càng, sau chạy chương trình nhận xét kết quảđể hiểu rõ nguyên tắc thao tác với file loại

character*20 st

OPEN(3, FILE='TEST6.TXT',RECL=10,FORM='BINARY', & ACCESS='DIRECT')

WRITE (3, REC=1) 'abcdefghijklmno' ! Ghi đè sang ghi thứ

WRITE (3) 4,5 ! Ghi vào ghi thứ

WRITE (3, REC=4) 'pq' CLOSE (3)

OPEN (3, FILE='TEST6.TXT',RECL=10,FORM='BINARY',& ACCESS='DIRECT')

read(3,rec=3) i,j ! Đọc ghi thứ

write(*,*) i,j

read(3,rec=1) st ! Đọc sang ghi thứ

print*,st

read(3,rec=2) st ! Đọc sang ghi thứ

write(*,*) st END

Cấu trúc liệu file mơ tả hình 7.8 Khi chạy chương trình ta nhận kết mong đợi Khai báo độ dài ghi 10 byte, biến st 20 byte, gấp hai lần độ dài ghi, nội dung st có 15 byte Khi ghi vào file, st chiếm hai ghi, ghi thứ hai chứa byte nội dung cuối st byte cịn lại có nội dung khơng xác định Do đó, đọc nội dung ghi thứ hai (rec=2) gán cho biến ký tự ta

nhận kết “klmno” Bản ghi thứ ba lưu hai số nguyên byte, nên dư byte không xác

định Tương tự ghi thứ

7.4 LỆNH MỞ (OPEN) VÀ ĐÓNG (CLOSE) FILE

Ta làm quen với lệnh mở file (OPEN) lệnh đóng file (CLOSE) qua ví dụ mà chưa giải thích thêm Trong mục ta khảo sát kỹ câu lệnh

7.4.1 Lệnh mở file

Một cách tổng quát, cú pháp câu lệnh mở file có dạng: OPEN ([UNIT=] unit

(136)

[, BLOCKSIZE=blocksize]

[, CARRIAGECONTROL=carriagecontrol] [, DELIM=delim]

[, ERR=err] [, FILE=file] [, FORM=form] [, IOFOCUS=iofocus] [, IOSTAT=iostat] [, PAD=pad]

[, POSITION=position] [, RECL=recl]

[, SHARE=share] [, STATUS=status])

Hình 7.8 Cấu trúc file TEST6.TXT

Trong mô tả đây, từ viết in hoa xem từ khoá xác định tham số, chúng phải viết cách xác, từ viết in thường sau dấu (=) giá trị tham số Nhưđã thấy, cú pháp đầy đủ câu lệnh phức tạp chứa nhiều tham số Tuy vậy, hầu hết tham số tùy chọn, ta bỏ qua tùy chọn khơng cần thiết q trình sử dụng Sau ý nghĩa cách sử dụng tham số

UNIT là tham số dùng để khai báo thiết bị lôgic sẽđược liên kết với file Nếu bỏ qua UNIT= unit cần phải tham sốđầu tiên Ngược lại, tham số xuất theo thứ tự

unit: Là một số nguyên (INTEGER(4)) lớn 0, dùng thiết bị lôgic để

liên kết với file thiết bị

access: Chỉ cách truy cập vào file, nhận giá trị “APPEND” (ghi tiếp vào cuối file), “DIRECT” (truy cập trực tiếp), “SEQUENTIAL” (truy cập tuần tự− ngầm định)

action: Là tham số mô tả tác động dựđịnh file Có thể nhận giá trị ‘READ’ (file đọc), ‘WRITE’ (chỉđể ghi vào file), 'READWRITE' (cảđọc từ file ghi vào file) Nếu bỏ qua action, chương trình cố gắng mở file với 'READWRITE' Nếu khơng được, trước hết chương trình mở file với 'READ', sau với 'WRITE' Việc bỏ qua action không giống với ACTION = 'READWRITE' Nếu ACTION = 'READWRITE', mà file truy cập cảđọc ghi việc mở file khơng thành cơng Do việc bỏ qua action mềm dẻo linh động

(137)

(ngầm định) để bỏ qua ký tự trống, giá trị 'ZERO' để xử lý ký tự trống (các dấu cách ởđầu) số

blocksize: Ngầm định số nguyên ((INTEGER(4)), dùng để biểu diễn kích thước vùng

đệm (tính byte)

carriagecontrol: Có dạng ký tự (Character*(*)), dùng để việc hiểu ký tựđầu tiên ghi file có định dạng nào; nhận giá trị 'FORTRAN' 'LIST' Ngầm

định UNIT kết nối với thiết bị máy in hình 'FORTRAN'; ngầm

định UNIT kết nối với file 'LIST' carriagecontrol bị bỏ qua sử dụng tùy chọn FORM= 'UNFORMATTED' FORM='BINARY'

delim: Có dạng ký tự (Character*(*)), dùng để cách định ranh giới ghi list-directed hoặc namelist-formatted; nhận giá trị 'APOSTROPHE', 'QUOTE', 'NONE' (ngầm định)

err: Là nhãn của câu lệnh thực chương trình Khi gặp lỗi mở file chương trình

chuyển điều khiển đến câu lệnh có nhãn err Nếu bỏ qua, hiệu ứng lỗi vào/ra xác định iostat

file: Có dạng ký tự (Character*(*)), dùng để tên file cần mở; dấu cách, tên file hợp lệ, tên thiết bị tên biến xác định file Đối với Windows NT Windows 9x trở lên, tên file cho phép dài ký tự, phần mở rộng dài ký tự Nếu filebị bỏ qua, trình biên dịch tạo file tạp nham (file nháp) có tên (khơng có phần mở rộng) file bị xóa gặp lệnh đóng file chương trình kết thúc

form: Xác định kiểu file sẽđược mở, nhận giá trị 'FORMATTED' (file có định dạng), 'UNFORMATTED' (file không định dạng), 'BINARY' (file nhị phân) Đối với file truy cập tuần tự, giá trị ngầm định 'FORMATTED'; file truy cập trực tiếp giá trị ngầm định 'UNFORMATTED'

iofocus: Tham số lơgic, dùng để việc có đặt cửa sổ (child window) cửa sổ hoạt động hay không Giá trị .TRUE (ngầm định) tạo lời gọi SETFOCUSQQ trước thực lệnh READ, WRITE, PRINT

iostat: Là tham số kết xuất, ngầm định số nguyên (INTEGER(4)); cho giá trị không xuất lỗi mở file, giá trị âm gặp lỗi kết thúc ghi, số xác định mã lỗi

pad: Có dạng ký tự (Character*(*)), dùng để việc có đệm dấu cách vào ghi

đọc hay khơng định dạng ghi có độ dài lớn độ dài liệu pad nhận giá trị 'YES' (ngầm định) 'NO' Tham số tác động đọc liệu

position: Có dạng ký tự (Character*(*)), vị trí trỏ file truy cập tuần tự, nhận giá trị 'ASIS' (ngầm định), 'REWIND', 'APPEND' Nếu position nhận giá trị

(138)

cuối file; nhận giá trị 'ASIS', trỏ file khơng thay đổi vị trí (tức giữ nguyên vị trí thời file) Vị trí trỏ file file ln ln ởđầu file

recl: Ngầm định số nguyên, để chỉđộ dài tính byte ghi file truy cập trực tiếp, độ dài ghi cực đại file Đối với file truy cập trực tiếp tham số đòi hỏi phải có

share: Có dạng ký tự (Character*(*)), quyền truy cập file mở Các giá trị

của share có ý nghĩa sau:

share ='DENYRW': Cấm đọc/ghi share ='DENYWR': Cấm ghi share ='DENYRD': Cấm đọc

share ='DENYNONE': Cho phép cảđọc ghi (ngầm định)

status: Có dạng ký tự (Character*(*)), dùng để mô tả trạng thái file mở Sau giá trị tham số

status = 'OLD': File tồn Mở thành công file tồn tại, ngược lại xuất lỗi; status='NEW': File Nếu file không tồn tạo Nếu file tồn

xuất lỗi;

status='SCRATCH': Nếu bỏ qua tham số file giá trị status ngầm định 'SCRATCH' File SCRATCH file tạm thời, bị xóa đóng file chương trình kết thúc;

status='REPLACE': File mở thay file có tên Nếu file tên khơng tồn file tạo

status='UNKNOWN' (ngầm định): Trong lúc chương trình chạy hệ thống cố gắng mở file với status = 'OLD', sau với status = 'NEW' Nếu file tồn mở, khơng tồn tạo Sử dụng status = 'UNKNOWN' để tránh lỗi xảy lúc chạy chương trình liên quan đến việc mở file tồn với status ='NEW' mở file không tồn với status = 'OLD'

Các giá trị statuschỉảnh hưởng tới file đĩa, bỏ qua thiết bị

bàn phím hình máy in 7.4.2 Lệnh đóng file

Cú pháp lệnh đóng file CLOSE có dạng: CLOSE ([UNIT=] unit

[, ERR=err] [, IOSTAT=iostat] [, STATUS=status])

Trong đó: UNIT= bị bỏ qua unit phải tham sốđầu tiên, ngược lại tham số

(139)

unit: Là một số nguyên thiết bị lôgic liên kết với file mở Sẽ không xuất lỗi file không mở

err: Là nhãn của câu lệnh thực chương trình sẽđược chuyển điều khiển tới lỗi xuất đóng file Nếu bỏ qua, hiệu ứng lỗi vào/ra xác định có mặt khơng có mặt tham số iostat

iostat: Là tham số kết xuất, ngầm định số nguyên (INTEGER*4), nhận giá trị khơng xuất lỗi đóng file, số mã lỗi

status: Tham số vào, biểu thức ký tự (CHARACTER*(*)), nhận giá trị “KEEP” “DELETE”; ngầm định “KEEP”, ngoại trừ file nháp Các file mở khơng có tham số FILE= được gọi file nháp (“scratch” files) Đối với file giá trị ngầm định status 'DELETE' Nếu đặt status ='KEEP' file nháp gây nên lỗi run-time

7.5 CÁC LỆNH VÀO RA DỮ LIỆU VỚI FILE

7.5.1 Lệnh đọc liệu từ file (READ) Cú pháp lệnh READ làm việc với file có dạng: READ { { fmt , | nml } |

( [UNIT=] unit [, { [FMT=] fmt | [NML=] nml } ] [, ADVANCE=advance] [, END=end]

[, EOR=eor] [, ERR=err] [, IOSTAT=iostat] [, REC=rec]

[, SIZE=size] ) } iolist

Trong dấu gạch đứng (|) dùng để phân chia tham số thuộc nhóm, có nghĩa phép chọn tham số nhóm Ví dụ, chọn [FMT=] fmt khơng được phép chọn [NML=] nml Nếu bỏ qua UNIT=, unit phải tham số Nếu bỏ qua FMT= NML=, fmt nml phải tham số thứ hai Nếu muốn sử dụng fmt khơng có FMT=, phải bỏ qua UNIT= Trong trường hợp khác tham số xuất theo thứ tự Hoặc fmthoặc nmlcần hai Sau ý nghĩa tham số

unit: Là tên thiết bị lơgic Khi đọc từ file ngồi unit biểu thức nguyên Khi đọc từ

một file unit xâu ký tự, biến ký tự phần tử mảng ký tự,

fmt: Là chỉ thịđịnh dạng, nhận trường hợp: 1) Nhãn lệnh FORMAT; 2) Biểu thức ký tự (biến, thủ tục, hằng) xác định định dạng đọc vào, phân định dấu nháy

(140)

UNIT=, END=, ERR=, REC=, có fmt iolist, câu lệnh đọc từ UNIT (*) bàn phím

nml: Chỉ tên NAMELIST Các tùy chọn iolist fmt phải bỏ qua Lệnh đọc NAMELIST có thểđược thực file truy cập

advance: Có dạng ký tự (Character*(*)), dùng để cách đọc vào từ file có định dạng, nhận giá trị 'YES' (ngầm định) 'NO' Nếu advance = ‘YES’: Chương trình sẽđọc theo

định dạng fmt hết ghi sang ghi khác gán giá trị cho iolist Nếu advance = ‘NO’: Chương trình sẽđọc giá trị theo định dạng dòng gán cho iolist Nếu số giá trị chứa ghi số biến iolist xuất lỗi Yêu cầu tham sốđịnh dạng fmt phải khác (*)

end: Nhãn của câu lệnh chương trình sẽđược chuyển điều khiển đến trỏ file đặt

cuối ghi kết thúc file Nếu bỏ quan end, xuất lỗi trỏ file cuối file trình đọc cố gắng đọc tiếp, trừ trường hợp có err iostat

eor: Nhãn của câu lệnh chương trình sẽđược chuyển điều khiển đến trỏ file đặt

cuối ghi Tham số dùng đưa vào tham số ADVANCE='NO' Nếu bỏ qua eor, hiệu

ứng lỗi vào/ra sẽđược xác định iostat

err: Nhãn của câu lệnh chương trình sẽđược chuyển đến gặp lỗi trình đọc Nếu bỏ qua err, hiệu ứng lỗi vào/ra sẽđược xác định iostat

iostat: Là tham số kết xuất, ngầm định số nguyên (INTEGER(4)) iostat = 0 khơng có lỗi, = 1 gặp kết thúc file (end-of-file), số thị thông báo lỗi

rec: Tham số vào, ngầm định số nguyên dương (INTEGER(4)) số thứ tự ghi cần

đọc file truy cập trực tiếp Sẽ xuất lỗi sử dụng tham số cho file truy cập

hoặc file Khi sử dụng tham số rec cần bỏ qua tham số endvà nml Con trỏ file sẽđược định vịđến ghi có số thứ tự rec trước liệu đọc Số thứ tự ghi Ngầm định rec số thứ tự ghi thời

size: Ngầm định số nguyên (INTEGER(4)), trả số lượng ký tựđược đọc chuyển cho biến nhận liệu vào Các dấu cách chèn đệm vào khơng tính Nếu sử dụng tham số

này cần phải đặt tùy chọn ADVANCE='NO'

iolist: Danh sách biến sẽđược nhận liệu từ file 7.5.2 Lệnh ghi liệu file (WRITE)

Cú pháp câu lệnh sau WRITE ( [UNIT=] unit

(141)

[, IOSTAT=iostat] [, REC=rec] ) iolist

Trong đó, dấu gạch đứng có ý nghĩa phân cách tham số nhóm mà chúng phép xuất

Nếu bỏ qua UNIT= unit phải tham số fmt nml phải tham số thứ hai (FMT= NML= có thểđược bỏ qua) Ngược lại, tham số xuất theo thứ tự Trong hai tham số fmtvà nml chỉđược phép xuất

unit: Là tên thiết bị lôgic Khi ghi file unit biểu thức nguyên gắn với định danh UNIT Khi ghi file unit phải xâu ký tự, biến ký tự, mảng phần tử mảng ký tự, Nếu unit chưa liên kết với file cụ thể lệnh mở file ẩn (implicit) thực Ví dụ câu lệnh sau:

OPEN (unit, FILE = ' ', STATUS = 'OLD',& ACCESS = 'SEQUENTIAL', FORM = form)

trong form 'FORMATTED' lệnh đọc/ghi có định dạng 'UNFORMATTED' lệnh đọc/ghi không định dạng

fmt: Chỉ thịđịnh dạng, nhãn câu lệnh FORMAT; biến, hàm ký tự, kiểu định dạng cặp dấu nháy đơn ( ' ) nháy kép ( " ); biến nguyên ASSIGN; dấu (*)

nml: Chỉ tên NAMELIST Nếu tham số chọn tham số iolist fmt phải

được bỏ qua File chứa NAMELIST phải file truy cập

advance: Có dạng ký tự (Character*(*)), cách ghi file tiến (advancing) hay không Nếu advance='YES' (ngầm định) tạo đánh dấu vị trí cuối ghi; advance='NO' sẽ ghi phần ghi (tức chưa tạo kết thúc ghi)

err: Nhãn của câu lệnh thực chương trình sẽđược chuyển điều khiển đến gặp lỗi Nếu bỏ qua tham số này, hiệu ứng lỗi vào/ra sẽđược xác định tham số iostat

iostat: Là tham số kết xuất, ngầm định số ngun (INTEGER(4)), khơng có lỗi, số xác định mã lỗi

rec: Tham số vào, ngầm định số nguyên dương (INTEGER(4)), số thứ tự ghi file sẽđược ghi vào file truy cập trực tiếp Khi sử dụng tham số rec tham số end nml cần phải bỏ qua Con trỏ file phải định vị ghi rec trước liệu ghi Giá trị ngầm

định rec số thứ tự ghi thời

(142)

7.5.3 Vào liệu với NAMELIST

Vào liệu NAMELIST phương pháp hữu hiệu Fortran Bằng cách

ra nhiều biến nhóm tên danh sách ta có thểđọc ghi giá trị chúng với câu lệnh đơn giản

Nhóm namelist tạo câu lệnh NAMELIST có dạng: NAMELIST / namelist / variablelist

Trong namelist tên nhóm variablelist danh sách biến

Lệnh NAMELIST đọc vào kiểm duyệt tên nhóm file NAMELIST Sau tìm thấy tên nhóm kiểm duyệt câu lệnh gán giá trị cho biến nhóm

Trong file NAMELIST, nhóm bắt đầu dấu (&) dấu đôla ($), kết thúc dấu gạch chéo (/), dấu (&), dấu đơla ($)

Từ khóa END xuất liền sau dấu kết thúc (&) ($) (khơng có dấu cách) khơng phép xuất sau dấu gạch chéo (/)

Ví dụ, giả sử có: INTEGER a, b

NAMELIST /mynml/ a, b

Các lệnh gán file NAMELIST sau hợp lệ: &mynml a = /

$mynml a = 1, b = 2, $ $mynml a = 1, b = 2, $end &mynml a = 1, b = 2, & &mynml a = 1, b = 2, $END &mynml

a = b = /

a Lệnh đọc nội dung NAMELIST Cú pháp:

READ (UNIT=unit, [NML=] namelist)

Trong unit thiết bị lơgic lưu trữ thơng tin NAMELIST, file đĩa bàn phím, namelist tên của NAMELIST Nếu unit dấu (*) NAMELIST nhận từ bàn phím Trong trường hợp cần phải gõ vào theo qui cách Ví dụ:

INTEGER a, b

NAMELIST /mynml/ a, b read(*,mynml)

(143)

Khi chạy chương trình ta phải gõ vào, chẳng hạn: &mynml a = 1, b = 2, /

Một ví dụ khác, giả sửNAMELIST có tên example chứa file liên kết với thiết bị lôgic (unit=4) với nội dung:

&example

Z1 = (99.0,0.0) INT1=99 array(1)=99 REAL1 = 99.0 CHAR1='Z'

CHAR2(4:9) = 'Inside' LOG1=.FALSE /

Ta dùng câu lệnh sau đểđọc nội dung NAMELIST này: READ (UNIT = 4, example)

Hoặc, giả sử ta có chương trình INTEGER, DIMENSION(4) :: A = NAMELIST /MYOUT/A, X, Y X =

Y =

PRINT*,'Cho noi dung NAMELIST (A(1:4),X,Y):' READ( *, MYOUT )

WRITE( *, NML = MYOUT ) END

Khi chạy chương trình ta nhập vào (từ bàn phím): &MYOUT A(1:2) = 2*1 Y = /

và nhận (trên hình):

&MYOUT A = 1 7, X = 1.0000000, Y = 3.0000000 b Lệnh in nội dung NAMELIST

Để in nội dung nhóm NAMELIST sử dụng lệnh: WRITE (UNIT=unit, [NML=] namelist)

NML= tùy chọn, chỉđịi hỏi phải có từ khóa khác sử dụng

Ví dụ, chương trình sau gán giá trị NAMELIST in nội dung lên hình INTEGER(1) int1

INTEGER int2, int3, array(3) LOGICAL(1) log1

(144)

NAMELIST /example/ int1, int2, int3, & log1, log2, log3, real1, real2, & z1, z2, char1, char2, array int1 = 11

int2 = 12 int3 = 14 log1 = TRUE log2 = TRUE log3 = TRUE real1 = 24.0 real2 = 28.0d0 z1 = (38.0, 0.0) z2 = (316.0d0, 0.0d0) char1 = 'A'

char2 = '0123456789' array(1) = 41

array(2) = 42 array(3) = 43

WRITE (*, example) END

Khi chạy chương trình ta nhận hình: &EXAMPLE

INT1 = 11 INT2 = 12 INT3 = 14 LOG1 = T LOG2 = T LOG3 = T

REAL1 = 24.000000 REAL2 = 28.000000

Z1 = (38.000000,0.000000E+00) Z2 = (316.000000,0.000000E+000) CHAR1 = A

CHAR2 = 0123456789

ARRAY = 41 42 43 /

Ta sửa đổi chương trình để ghi NAMELIST vào file 7.5.4 Một số ví dụ thao tác với file

1) Chương trình sau tạo file có tên file ta xác định, sau đọc nội dung ghi file hỏi ta có xóa hay khơng Kết trung gian ghi vào file nháp Nội dung file tạo sẽđược phục hồi lại từ file nháp

CHARACTER(80) Name, FileName, Ans

(145)

OPEN( 1, FILE = FileName ) OPEN( 2, STATUS = 'SCRATCH' ) write (1,'(A)') 'TEST1 Only'

write (1,'(A)') 'TEST2 Only' write (1,'(A)') 'TEST3 Only' rewind(1)

IO =

DO WHILE (IO == 0)

READ( 1, '(A)', IOSTAT = IO ) Name print*,Name

IF (IO == 0) THEN

WRITE(*,'(A)',ADVANCE='NO')“Xoa khong (Y/N)?" READ*, Ans

IF(Ans/='Y'.AND.Ans/='y') WRITE( 2, * ) Name END IF

END DO REWIND( )

CLOSE( 1, STATUS = 'DELETE' ) OPEN( 1, FILE = FileName ) IO =

DO WHILE (IO == 0)

READ( 2, '(A)', IOSTAT = IO ) Name IF (IO == 0) WRITE( 1, * ) Name END DO

CLOSE( ) CLOSE( ) END

2) Chương trình sau tạo file không định dạng Chú ý cách truy cập đến ghi

INTEGER, DIMENSION(10) :: A = (/ (I, I = 1,10) /) INTEGER, DIMENSION(10) :: B = (/ (I, I = 11,20) /) OPEN( 1, FILE = 'TEST', FORM = 'UNFORMATTED' ) WRITE (1) A ! ghi A trước

WRITE (1) B ! ghi B sau REWIND (1)

A = B =

READ (1) B ! đọc B trước PRINT*, B

READ (1) A ! đọc A sau PRINT*, A

CLOSE (1) END

3) Chương trình sau tạo file truy cập trực tiếp CHARACTER (20) NAME

(146)

OPEN( 1, FILE = 'TEST.txt', STATUS = 'REPLACE',& ACCESS = 'DIRECT', RECL = LEN )

DO I = 1,

PRINT*,' Cho xau ky tu thu ', I READ*, NAME

WRITE (1, REC = I) NAME END DO

PRINT*,' Cac xau da nhap:' DO I = 1,

READ( 1, REC = I ) NAME PRINT*,'Xau thu ',I,': ', NAME END DO

! Ghi de (thay doi) noi dung ban ghi thu WRITE (1, REC = 3) 'Ban ghi thu 3' PRINT*,' Cac xau sau sua doi:' DO I = 1,

READ( 1, REC = I ) NAME PRINT*, NAME

END DO CLOSE (1) END

4) Chương trình sau đọc ký tự ghi in nội dung số ký tự ghi Hãy lưu ý cách sử dụng tham số lệnh READ

CHARACTER ch*1, ST(100) INTEGER IO, Num, EOR OPEN( 1, FILE = 'TEST.TXT' ) DO I=1,10

WRITE(1,'(10I3)') (J,J=I+1,I+10) END DO

REWIND (1) IO =

DO WHILE (IO /= -1) ! EOF

! DO WHILE (IO == 0) ! Khong co loi Num =

do

READ (1, '(A1)', IOSTAT = IO,&

ADVANCE = 'NO',EOR=10) ch ! Doc tung ky tu Num = Num +

ST(Num) = ch ! Luu vao bien ST end

10 PRINT*,Num ! In so ky tu PRINT*,ST ! In noi dung ban ghi END DO

CLOSE (1) END

(147)

cùng dòng Chú ý cách tạo lệnh định dạng FORMAT cho in số phần tử độ rộng trường tùy ý

INTEGER WI, N(10), ICOUNT, XCOUNT REAL X(10)

ICOUNT=1 DO

PRINT*,' CHO GIA TRI N(',ICOUNT,') (-999=THOAT):' READ*,N(ICOUNT)

IF (N(ICOUNT)==-999.OR.ICOUNT==10) EXIT ICOUNT=ICOUNT+1

END DO XCOUNT=1 DO

PRINT*,' CHO GIA TRI X(',XCOUNT,') (-999=THOAT):' READ*,X(XCOUNT)

IF (X(XCOUNT)==-999.OR.XCOUNT==10) EXIT XCOUNT=XCOUNT+1

END DO

PRINT*,' CHO DO RONG TRUONG SO NGUYEN:' READ*, WI

WRITE(*, 11) (X(I),I=1,XCOUNT-1) 11 FORMAT(2X,<XCOUNT-1>F8.1) WRITE(*, 10) (N(I),I=1,ICOUNT-1) 10 FORMAT(<ICOUNT-1>I <WI>) WRITE(*,*)

END

BÀI TẬP CHƯƠNG

7.1 Khảo sát đoạn chương trình sau cho biết cấu trúc file xử lý: INTEGER, PARAMETER :: NX=201, NY=161, NZ=16

INTEGER NDIG, MDIG CHARACTER :: FMT*20

REAL*4 X (NX, NY, NZ), OUT(NX, NY)

OPEN (1, FILE=”RAIN.DAT”, FORM=”UnFormatted”,& ACCESS=”Direct”, RECL=NX*NY*4, STATUS=”Old”) DO K=1,NZ

READ(1,REC=K) OUT X(:,:,K) = OUT(:,:) END DO

OPEN (3, FILE=”RAIN.TXT”,STATUS=”UnKnown”) NDIG=12

MDIG=4

WRITE(FMT,"(A,I3.3,A,I2.2,A,I1,A)") & '(', NX,'F', NDIG,'.', MDIG,')' DO J=NY, 1, 1

(148)

END DO END

7.2 Khảo sát đoạn chương trình sau cho biết cấu trúc file xử lý: INTEGER NX, NY, NZ

REAL*4 X (NX, NY, NZ), OUT(NX, NY)

OPEN (1, FILE=”DATA.TXT”,STATUS=”Old”) READ (1, *) NX, NY, NZ

DO K=1, NZ DO J=1,NY

READ (1,*) (X(I,J,K), I=1,NX) END DO

END DO

OPEN (3, FILE=”DATA.DAT”, FORM=”UnFormatted”,& STATUS=”UnKnown”)

DO K=1,NZ

OUT (:,:) = X(:,:,K) WRITE (3) OUT END DO

END

7.3 Cho file số liệu dạng TEXT chứa kết quan trắc biến X1, X2, …, Xm Cấu trúc

file sau Dòng tiêu đề mơ tả nội dung file Dịng hai số nguyên dương (N, M) số lần quan trắc (N − dung lượng mẫu) số biến (M) Các dòng dòng chứa M số thực giá trị

quan trắc xi1, xi2, …, xim lần thứ i (i=1,2,…,N) biến X1, X2, …, Xm, giá trịđược viết cách

nhau dấu cách Hãy viết chương trình đọc file số liệu ghi vào file theo qui cách không định dạng truy cập với đầy đủ nội dung file cho trừ dòng tiêu đề

7.4 Viết chương trình đọc file khơng định dạng truy cập tuần tựđã tạo tập 7.3 ghi vào file theo qui cách không định dạng truy cập trực tiếp Hãy kiểm tra lại kết cách

đọc lại

7.5 Cho file số liệu dạng TEXT chứa kết quan trắc biến Y (biến phụ thuộc) biến X1, X2, …, Xm (biến độc lập) Cấu trúc file sau Dịng tiêu đề mơ tả nội dung file Dòng

hai số nguyên dương (N, M) số lần quan trắc (N − dung lượng mẫu) số biến độc lập (M) Các dòng dòng chứa M+1 số thực giá trị quan trắc yi, xi1, xi2, …, xim lần thứ i (i=1,2,…,N)

của biến Y, X1, X2, …, Xm, giá trịđược viết cách dấu cách Hãy viết chương

trình đọc file số liệu vào ghi vào file theo qui cách định dạng nhị phân (BINARY) truy cập với đầy đủ nội dung file cho, kể dòng tiêu đề

(149)

7.7 Viết chương trình tạo file khơng định dạng truy cập trực tiếp chứa 20 mảng chiều gồm số nguyên, kích thước mảng 10 Đọc mảng thứ 5, 10, 15 20 từ file in để kiểm tra

7.8 Viết chương trình nhập vào mảng chiều kích thước 10 phần tử số nguyên thay nội dung mảng thứ thứ 10 file tạo tập 7.7 tương ứng hai mảng

(150)

CHƯƠNG MỘT SỐ KIẾN THỨC MỞ RỘNG 8.1 KHAI BÁO DÙNG CHUNG BỘ NHỚ

Trong nhiều lớp toán, vấn đề dùng chung nhớ định khả giải toán liên quan đến tài nguyên nhớ tốc độ máy tính Fortran hỗ trợ vài phương thức dùng chung nhớ, làm tăng khả chia sẻ liệu đơn vị chương trình làm tăng tốc

độ truy cập nhớ Trong mục ta xét hai phương thức dùng chung nhớ sử dụng lệnh COMMON lệnh EQUIVALENT

8.1.1 Lệnh COMMON

Cú pháp câu lệnh COMMON có dạng: COMMON [/[cname]/] list [ [,]/[cname]/ list]

Trong đó: cname: (Tùy chọn) tên khối dùng chung mà biến list thuộc khối Nếu bỏ qua ta nói khối chung “trắng” (“blank common”); list: Là nhiều tên biến, tên mảng phép dùng chung vùng nhớ, chúng liệt kê cách dấu phẩy

Các biến, mảng khối dùng chung đơn vị chương trình phải tương ứng vị

trí độ dài Các mảng phải có kích thước Các biến khối chung đối số hình thức, mảng động, tên hàm, Chúng khai báo lệnh PARAMETER

Tác động khối dùng chung chỗ, đơn vị chương trình khác có khai báo dùng chung tên khối chung cname thì, danh sách tên biến cname đơn vị

chương trình khác nhau, chúng tham chiếu đến vùng nhớ Ví dụ, giả sử ta có đơn vị chương trình sau:

PROGRAM MyProg COMMON i, j, x, k(10) COMMON /mycom/ a(3) A=5

CALL MySub PRINT*,A END !

SUBROUTINE MySub

COMMON je, mn, z, idum(10) COMMON /mycom/ B(3) B = B +

(151)

Khi chương trình thực hiện, biến je, mn, z, idum MySub tham chiếu đến vùng nhớ tương ứng biên I, J, X, K MyProg; biến B MySub biến A MyProg dùng chung vùng nhớ Do đó, lời gọi CALL MySub B bị thay đổi có nghĩa A bị biến đổi

8.1.2 Lệnh EQUIVALENT

Phương thức khai báo dùng chung EQUIVALENCE làm cho hai nhiều biến mảng chiếm vùng nhớ Cú pháp câu lệnh có dạng:

EQUIVALENCE (nlist) [, (nlist)]

Trong nlist hai nhiều biến, mảng phần tử mảng, viết cách dấu phẩy (,) Các số mảng cần phải số nguyên phải nằm miền giá trị kích thước mảng Những tên biến mảng khơng có sốđược ngầm hiểu phần tử có sốđầu tiên mảng Tất phần tử nlist có vị trí vùng nhớ Để minh họa ta xét ví dụ sau

Giả sử ta có khai báo:

CHARACTER a*4, b*4, c(2)*3 EQUIVALENCE (a, c(1)), (b, c(2)) Khi định vị nhớ có dạng:

01 02 03 04 05 06 07 A

B

C(1) C(2) Nếu không khai báo dùng chung, dung lượng nhớ phải cấp cho biến A, B, C 4 + + 2*3 = 14 byte Nhưng sử dụng khai báo dùng chung EQUIVALENT, dung lượng nhớ

cấp cho biến cần 7 byte hình vẽ Từ hình vẽ, hình dung rằng, 3 ký tự phần tửC(1) dùng chung nhớ với 3 ký tựđầu xâu A; ký tự thứ tư xâu A, ký tự thứ xâu B ký tự thứ phần tửC(2) dùng chung 1 byte; hai cặp ký tự xâu B C(2) dùng chung byte thứ5 thứ6; có ký tự cuối xâu B khơng dùng chung Do

đó, tùy theo biến bị thay đổi giá trị cuối mà biến khác bị biến đổi theo Ví dụ, khai báo trên, câu lệnh là:

A=‘abcd’ B=‘efgh’ C(1)=‘ijk’ C(2)=‘LMN’ kết cuối là:

C(1)=‘ijk’ B=‘LMNh’

(152)

Một ví dụ khác, giả sử ta có chương trình: INTEGER M(6), N(10), MN(8)

EQUIVALENCE (N,M), (N(7),MN) N=4

M=3 MN=5 PRINT*,M PRINT*,N PRINT*,MN END

Khi chạy chương trình ta nhận kết quả: MN=(5, 5, 5, 5, 5, 5, 5, 5)

N =(3, 3, 3, 3, 3, 3, 5, 5, 5, 5) M =(3, 3, 3, 3, 3, 3)

8.2 CHƯƠNG TRÌNH CON BLOCK DATA

Chương trình BLOCK DATA loại đơn vị chương trình cho phép xác định giá trị

khởi tạo cho biến khối dùng chung Chương trình chứa câu lệnh khơng thực Cấu trúc chương trình có dạng:

BLOCK DATA [name] [Các_câu_lnh]

END [BLOCK DATA [name]]

Thông thường biến khởi tạo lệnh DATA Các biến khối dùng chung khởi tạo BLOCK DATA chứa câu lệnh: COMMON, USE, DATA, PARAMETER, DIMENSION, POINTER, EQUIVALENCE, SAVE, IMPLICIT

Ví dụ:

COMMON /WRKCOM/ X, Y, Z (10,10) PRINT*,X

PRINT*,Y PRINT*,Z END

BLOCK DATA WORK

COMMON /WRKCOM/ A, B, C (10,10) DATA A /1.0/, B /2.0/ , C /100*5.0/ END BLOCK DATA WORK 8.3 CÂU LỆNH INCLUDE

Trong nhiều trường hợp, sốđoạn chương trình chuẩn hóa, thay đổi, xuất đơn vị chương trình khác nhau,… chúng chưa đủ để tạo lập riêng chương trình con, ta tách chúng đoạn gồm dòng lệnh liên tiếp ghi vào file riêng biệt Sau thay vào vị trí đoạn chương trình câu lệnh INCLUDE để “trả lại” nội dung nguyên Cú pháp câu lệnh sau

(153)

trong filename ký tự tên file, bao gồm cảđường dẫn, chứa nội dung đoạn chương trình tách từđơn vị chương trình Cách làm giúp ta tổ chức chương trình gọn nhẹ, dễ bao quát Khi gặp lệnh INCLUDE trình biên dịch tìm đến file có tên filename chèn nội dung file vào vị trí dịng lệnh tiến hành biên dịch với đơn vị chương trình Như vậy, tác dụng lệnh INCLUDE làm cho chương trình gọn hình thức

Ví dụ, giả sử ta có file “PARAM.INC” lưu thư mục thời với nội dung là: INTEGER, PARAMETER :: NMAX=200, MMAX=100

REAL, PARAMETER :: Re=6731, G=9.8 Khi chương trình sau đây:

PROGRAM CT1

INCLUDE “PARAM.INC”

END

sẽ tương đương với chương trình PROGRAM CT2

INTEGER, PARAMETER :: NMAX=200, MMAX=100 REAL, PARAMETER :: Re=6731, G=9.8

END

8.4 LỆNH INQUIRE

Chức câu lệnh truy vấn trạng thái, thuộc tính file dung lượng chiếm giữ nhớ biến Cú pháp tổng quát câu lệnh dài, tương tự câu lệnh OPEN Ởđây đưa ba dạng đơn giản với tham số tùy chọn thường sử dụng

Dạng 1:

INQUIRE (FILE = Tên_file, Tùy_chn = Chn) Dạng 2:

INQUIRE ([UNIT = ] Unit, Tùy_chn = Chn) Dạng 3:

INQUIRE (INLENGTH = Len) vname

Trong đó: Tên_file tên file sẽđược truy vấn; UNIT định danh số hiệu file; Unit số hiệu file; Chn biến nhận giá trị trả Tùy_chn; vname là tên biến/bản ghi; Len dung lượng chiếm giữ nhớ (độ dài) biến/bản ghi; Tùy_chn tham số tùy chọn,

nhận dạng sau (kiểu liệu trả vềđược viết dấu ngoặc đơn tương ứng): EXIST (logical): TRUE file tồn tại, FALSE file không tồn

(154)

NAMED (logical): TRUE file đặt tên, FALSE file chưa đặt tên NAME (character): Trả tên file file đặt tên

ACCESS (character): Nhận giá trịSEQUENTIAL, DIRECT, UNDEFINED (nếu chưa kết nối)

SEQUENTIAL DIRECT (character): Nhận giá trịYES, NO UNKNOWN, tùy thuộc kiểu truy cập cho phép

FORM (character): Nhận giá trịFORMATTED, UNFORMATTED, UNDEFINED RECL (integer): Độ dài cực đại ghi

NEXTREC (integer): Số thứ tự ghi vừa đọc ghi

POSITION (character): REWIND, APPEND, ASIS UNDEFINED (như lệnh OPEN) ACTION (character): READ, WRITE, READWRITE UNDEFINED

READ, WRITE READWRITE (character): YES, NO UNKNOWN

Ví dụ 8.1 Chương trình sau đòi hỏi ta nhập vào tên file kiểm tra tồn file Nếu file có tên nhập vào khơng tồn tại, chương trình yêu cầu nhập lại tìm thấy file ta muốn để kiểm tra lại

CHARACTER*80 fname CHARACTER answer LOGICAL exists, OK OK = FALSE

DO WHILE (.NOT.OK)

WRITE (*, '(1X, A\)') ' Cho ten file : ' READ (*, '(A)') fname

INQUIRE (FILE = fname, EXIST = exists) IF (.NOT exists) THEN

WRITE(*,'(2A)')' Khong tim thay file ', fname WRITE (*,'(A\)')' Nhap lai hay thoat (L/T)? ' READ (*,'(A)') answer

IF (answer == 't'.OR.answer == 'T') OK=.TRUE END IF

END DO END

Ví dụ 8.2 Chương trình sau trả dung lượng nhớ chiếm giữ biến mảng X tùy thuộc vào kích thước mảng mà ta nhập vào cho biến N

REAL, ALLOCATABLE :: X(:) INTEGER N, LEN

WRITE (*,'(A\)') ' Cho kich thuoc mang (N): ‘ READ*, N

ALLOCATE (X(N))

INQUIRE (IOLENGTH = LEN) X

(155)

END

8.5 ĐIỀU KHIỂN CON TRỎ FILE

8.5.1 Lệnh REWIND

Chức lệnh định vị lại trỏ file vị trí đầu file, bất chấp vị

trí Cú pháp câu lệnh sau REWIND {unit|([UNIT=]unit & [,ERR=err][,IOSTAT=iostat])}

Trong bỏ qua UNIT= unit phải tham sốđầu tiên unit số hiệu file, file chưa

được mở REWIND khơng có hiệu lực err nhãn câu lệnh thực chương trình; ra, xuất lỗi vào/ra, chương trình chuyển điều khiển đến câu lệnh có nhãn iostat nhận giá trị lệnh thực thành công, ngược lại trả số nguyên biểu diễn mã lỗi

8.5.2 Lệnh BACKSPACE

Chức lệnh đưa trỏ file lùi ghi so với vị trị thời Cú pháp câu lệnh là:

BACKSPACE {unit([UNIT=]unit[,ERR=err] & [,IOSTAT=iostat])}

Ý nghĩa tham sốởđây tương tự nhưđối với lệnh REWIND 8.5.3 Lệnh ENDFILE

Chức lệnh ghi vào vị trị thời trỏ file ghi kết thúc file Cú pháp câu lệnh là:

ENDFILE {unit | ([UNIT=] unit [, ERR=err] & [, IOSTAT= iostat] )}

Ý nghĩa tham sốởđây tương tự nhưđối với lệnh REWIND lệnh BACKSPACE Ví dụ 8.3 Chương trình sau cho thấy tác dụng câu lệnh REWIND, BACKSPACE ENDFILE

CHARACTER (LEN=50) ST

OPEN (1, FILE = “TEST.TXT”) ! Mở file

WRITE (1,”(A)”) “Dong 1” WRITE (1,”(A)”) “Dong 2” WRITE (1,”(A)”) “Dong 3”

WRITE (1,”(A)”) “Dong 4” ! File có ghi tất

REWIND (1) ! Đưa trỏ file vềđầu file

READ (1,”(A)”) ST

PRINT*, ST ! Kết hình là: Dong READ (1,”(A)”) ST

PRINT*, ST ! Kết hình là: Dong READ (1,”(A)”) ST

(156)

BACKSPACE (1) ! Lùi lại ghi vừa đọc (Dong 3) READ (1,”(A)”) ST

PRINT*, ST ! Kết hình là: Dong

BACKSPACE (1) !Lùi lại ghi vừa đọc (vẫn là Dong 3) ENDFILE (1) ! Ghi ghi kết thúc file vào vị trí

! Dong (File ghi đầu)

CLOSE (1) END

8.6 CẤU TRÚC DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA

Cho đến giới hạn xét kiểu liệu Fortran Ta biết cách sử dụng biến đơn biến mảng với kiểu liệu để giải nhiều toán khác Tuy nhiên chừng mực ta xem mảng loại cấu trúc liệu mà tập hợp phần tử gồm kiểu liệu đơn giản

Để hỗ trợ người dùng tạo kiểu liệu tùy ý, Fortran 90 cho phép ta tự thiết kế cấu trúc liệu cho riêng Trong mục ta xét cách tạo cấu trúc liệu kiểu

cách truy cập, sử dụng chúng lập trình

Trước hết ta xét ví dụ Giả sử ta muốn tạo ghi chứa thông tin sinh viên trường Trên thực tế, hồ sơ sinh viên gồm nhiều mục, ta xét số thơng tin chính, họ tên, địa chỉ, sốđiện thoại, mã số sinh viên, giới tính, ngày sinh, điểm môn học kể từ năm thứ lúc trường Khi ta định nghĩa ghi lưu trữ thông tin sinh viên sau:

TYPE HOSOSV

CHARACTER (30) HoTen ! bao gom ca ho va ten CHARACTER (20), DIMENSION(4) :: DiaChi ! Tinh, huyen, xa, thon/xom

CHARACTER (10) DienThoai

CHARACTER (9) MaSo ! Vi du, K45003504 LOGICAL GioiTinh ! TRUE neu la Nu, ! FALSE doi voi Nam (!) INTEGER NgaySinh ! Vi du, 19870308

REAL, DIMENSION(40) :: Diem ! Diem cac mon hoc END TYPE

Trong đoạn chương trình trên, TYPE từ khóa, dùng để định nghĩa cấu trúc HOSOSV Ta gọi HOSOSVđược định nghĩa kiểu liệu có cấu trúc Các biến khai báo nằm TYPE END TYPEđược gọi thành phần, hay trường, cấu trúc

Để khai báo biến có kiểu liệu ta viết: TYPE (HOSOSV) SVien

(157)

DiaChi cũng mảng ký tự gồm phần tử, phần tử xâu có độ dài 20 ký tự Để tham chiếu đến trường ta sử dụng dấu phần trăm (%) nối tên biến tên trường tương ứng Ví dụ, câu lệnh sau gán giá trị cho trường:

SVien%HoTen = “Hoang Anh Dung” SVien%DiaChi(1) = “Ha Noi”

SVien%DiaChi(2) = “Hoan Kiem” SVien%DiaChi(3) = “Hang Bac”

SVien%DiaChi(4) = “Dinh Tien Hoang” SVien%GioiTinh = FALSE

Ta khai báo biến mảng có kiểu HOSOSV theo cách tương tự nhưđối với kiểu liệu khác Fortran Ví dụ, để lưu trữ hồ sơ sinh viên lớp không 100 người ta khai báo:

TYPE (HOSOSV), DIMENSION (100) :: K45_KTTV

Khi K45_KTTV biến mảng gồm tối đa 100 phần tử, phần tử có kiểu HOSOSV Bởi vậy, câu lệnh

K45_KTTV%GioiTinh = FALSE

sẽ gán trường GioiTinh cho tất 100 sinh viên Nam (!) Câu lệnh gán tương đương với câu lệnh:

K45_KTTV(:)%GioiTinh = FALSE

Từđó, ta có thểđưa cú pháp định nghĩa kiểu liệu có cấu trúc sau: TYPE [[, Quyen_truy_cap] ::] Ten_Cau_Truc

[ PRIVATE | SEQUENCE]

Kieu_DL [, Thuoc_tinh [::]] Ten_truong1

Kieu_DL [, Thuoc_tinh [::]] Ten_truong2

END TYPE [Ten_Cau_Truc]

Trong Quyen_truy_cap ngầm định PUBLIC, trừ khai báo PRIVATE modul Còn câu lệnh khai báo PRIVATE xuất kiểu cấu trúc liệu định nghĩa modul Nếu Quyen_truy_cap PRIVATE kiểu cấu trúc, kể tên trường nó, truy cập modul chủ Nếu câu lệnh PRIVATE xuất khai báo kiểu cấu trúc tất trường chỉđược phép truy cập modul chủ Nếu câu lệnh SEQUENCEđược tất trường lưu trữ theo trình tựđã liệt kê

Giả sử ta định nghĩa cấu trúc mới: TYPE Student_Type

CHARACTER (20) NAME REAL Mark

END TYPE

(158)

Kiểu cấu trúc đơn giản có hai trường họ tên (NAME) điểm (Mark) Trong trường hợp này, để gán giá trị cho trường ta sử dụng cách tham chiếu sau:

Student = Student_Type( "Hoang Nam", 9.5 )

Giá trị trường câu lệnh gán cần phải xuất theo thứ tự định nghĩa kiểu Với cấu trúc HOSOSV ví dụ trước, việc truy cập gán giá trị cho trường phức tạp Ví dụ, chương trình sau gán nội dung thơng tin đầy đủ sinh viên theo mẫu cấu trúc

liệu HOSOSV:

TYPE HOSOSV CHARACTER (30) HoTen

CHARACTER (20), DIMENSION(4) :: DiaChi CHARACTER (10) DienThoai

CHARACTER (9) MaSo

LOGICAL GioiTinh ! TRUE neu la Nu, ! FALSE doi voi Nam (!) INTEGER NgaySinh ! Vi du, 19870308

REAL, DIMENSION(5) :: Diem ! Diem mon hoc END TYPE

TYPE (HOSOSV) SVien

SVien = HOSOSV(”Hoang Nam”,(/”Ha Noi”,”Hoan Kiem”,& ”Hang Bac”, ”Dinh Tien Hoang”/), &

“048234567”, ”KT04505432”, & .FALSE., 19780203, (/6,9,8,10,8/)) Print*, SVien

END

Giá trị ban đầu biến thuộc kiểu liệu có cấu trúc có thểđược khởi tạo qua câu lệnh khai báo, ví dụ:

TYPE (Student_Type) :: Student = &

Student_Type( "Hoang Nam", 9.5 )

Việc kết xuất thông tin biến thuộc kiểu liệu có cấu trúc thực nhưđối với biến có kiều liệu Ví dụ:

PRINT '(A20, F6.1)', Student

PRINT *, Student%Name

Nếu hai biến có kiểu liệu có cấu trúc ta thực câu lệnh gán chúng Khi nội dung tất trường hai biến sẽđược gán tương ứng cho Ví dụ:

TYPE Student_Type CHARACTER (20) NAME REAL Mark

END TYPE

(159)

Student1 = Student_Type( "Hoang Nam", 9.5 ) Student2 = Student1

END

Ngoài ra, ta có thểđịnh nghĩa kiểu liệu có cấu trúc phức tạp mà trường kiểu kiểu định nghĩa trước Chẳng hạn, kiểu HOSOSV đây, ta có thểđịnh nghĩa lại sau:

!

TYPE Name ! Ho ten CHARACTER (7) Ho CHARACTER (20) Dem CHARACTER (7) Ten END TYPE Name TYPE Address

CHARACTER (20) Tinh CHARACTER (20) Huyen CHARACTER (20) Xa CHARACTER (20) Xom END TYPE Address TYPE DiemHK

REAL, DIMENSION (10) :: HK1, HK2 END TYPE DiemHK

TYPE KetQuaHT

TYPE (DiemHK) NamThu1, NamThu2, NamThu3, NamThu4 END TYPE KetQuaHT

TYPE HOSOSV1 TYPE (Name) HoTen TYPE (Address) DiaChi

CHARACTER (10) DienThoai CHARACTER (9) MaSo

LOGICAL GioiTinh ! TRUE = Nu, FALSE = Nam INTEGER NgaySinh ! Vi du, 19870308

TYPE (KetQuaHT) Diem END TYPE

TYPE (HOSOSV1) SVien

SVien%HoTen = Name (“Tran”, “Luu”, “Danh”)

SVien%Diem%NamThu1%HK1 = (/10,8,8,7,9,6,7,8,9,10/)

Trở lại với toán việc lưu trữ hồ sơ sinh viên Hãy tưởng tượng ta có tập hồ sơ

(160)

hơn, cột nhỏ lại có cột nhỏ v.v Ví dụ, với cấu trúc đây, cột địa

bao gồm ba cột Cột điểm có bốn cột ứng với bốn năm học, năm học lại chia thành hai học kỳ, cột điểm có ba “tầng”,… Với suy luận ta thiết kế xây dựng cấu trúc liệu phù hợp chứa đầy đủ thông tin sinh viên

BÀI TẬP CHƯƠNG

8.1 Viết chương trình nhập hai mảng hai chiều A(N,M) B(M,P), thực phép nhân hai ma trận In ma trận A, B ma trận tích Yêu cầu: Nhập ma trận, nhân ma trận in ma trận tổ chức thành chương trình chương trình chương trình phải dùng chung nhớ

8.2 Một tập số liệu lịch sử nhiều năm lưu trữ thông tin bão hoạt động khu vực, gồm: Tên bão (tên quốc tế) xâu ký tự dài tối đa 20 ký tự, số thứ tự bão năm (số nguyên dương), ngày tháng năm hình thành tan rã, vị trí tâm bão đổ bổ vào đất liền (nếu có) cặp hai số thực kinh độ vĩđộ tâm bão, áp suất tâm vào thời điểm mạnh nhất, tốc độ gió cực đại vào thời điểm mạnh nhất, bán kính ảnh hưởng (là số thực) Hãy viết chương trình tổ

chức số liệu bão cho thuận tiện truy cập, khai thác Gi ý: Sử dụng kiểu liệu có cấu trúc TYPE

(161)

CHƯƠNG MỘT SỐ BÀI TỐN THƠNG DỤNG

Trong chương trình bày cách lập chương trình giải số tốn thường gặp thực tế ngôn ngữ Fortran Nhưđã nói trước đây, chương trình viết chương chủ

yếu nhấn mạnh khía cạnh lập trình, nghĩa trọng vào việc sử dụng ngôn ngữ Fortran, mà chưa đề

cập đến tối ưu thuật tốn Sau thành thạo ngơn ngữ, bạn đọc thay đổi chương trình để tạo thành thư viện cho riêng Vì hạn chế trình độ kiến thức nên

ởđây giới thiệu số toán sau:

− Lớp toán thống kê, bao gồm tính đặc trưng thống kê đơn giản, tính hệ số tương quan tuyến tính (tương quan cặp, tương quan bội, tương quan riêng), xây dựng phương trình hồi qui,…

− Các tốn giải tích số, tìm nghiệm phương trình, tính đạo hàm, tích phân, phương trình truyền nhiệt,…

− Xây dựng sở liệu

Hơn nữa, để tiện trình bày, chương trình viết kèm theo phần giới thiệu thuật tốn 9.1 CÁC BÀI TỐN THỐNG KÊ CƠ BẢN

9.1.1 Tính trung bình số học chuỗi số liệu

Giả sử có chuỗi số liệu x1, x2, , xn Khi trung bình số học chuỗi tính cơng thức:

=

= n

i i x n x

1

1

(9.1.1) Chương trình tính x viết dạng chương trình hàm AVER:

FUNCTION AVER(X,N)

! HAM TINH TRUNG BINH SO HOC CUA CHUOI

! INPUT: + X MANG DO DAI N CHUA SO LIEU QUAN TRAC ! + N DUNG LUONG MAU

! OUTPUT: TRUNG BINH SO HOC CUA X !

INTEGER N, I

REAL X(N) ! Mảng chứa số liệu ban đầu

REAL TMP TMP = X(1) DO I = 2,N

TMP = TMP + X(I) END DO

(162)

RETURN

END FUNCTION

9.1.2 Tính độ lệch chuẩn chuỗi số liệu

Bên cạnh trung bình số học, đặc trưng khác quan tâm xử lý số liệu độ lệch chuẩn Giả sử có chuỗi số liệu x1, x2, , xn Độ lệch chuẩn chuỗi bậc hai phương sai mẫu (hay phương sai thực nghiệm) tính cơng thức:

( ) ( )2

2

2

1

x x n x

x n

s n

i i n

i i

x = ∑ − = ∑ −

= =

(9.1.2)

Theo cơng thức này, để tính độ lệch chuẩn cần phải tính trung bình số học chuỗi Do đó, chương trình sau, hàm AVER sẽđược gọi tới

FUNCTION STDEV (X,N)

! HAM TINH DO LECH CHUAN CUA CHUOI X

! INPUT: + X MANG DO DAI N CHUA SO LIEU QUAN TRAC ! + N DUNG LUONG MAU

! OUTPUT: DO LECH CHUAN CUA X

! FUNCTION/SUBROUTINE DUOC GOI TOI: AVER(X,N) INTEGER N, I

REAL X(N) ! Mảng chứa số liệu ban đầu

REAL TMP, TMP1 TMP = X(1)*X(1) DO I = 2,N

TMP = TMP + X(I)*X(I) END DO

TMP1 = AVER(X,N)

STDEV = SQRT(TMP/REAL(N) - TMP1*TMP1) RETURN

END FUNCTION

9.1.3 Sắp xếp chuỗi theo thứ tự tăng dần xác định giá trị lớn nhất, nhỏ chuỗi Giả sử có chuỗi số liệu x1, x2, , xn Cần phải xếp chuỗi theo trình tự định xác

định giá trị lớn nhất, nhỏ chuỗi Trong nhiều trường hợp, toán thống kê, người ta thường xếp chuỗi theo thứ tự tăng dần Chuỗi xếp theo thứ tự tăng dần gọi chuỗi trình tự Hay nói cách khác, chuỗi trình tự chuỗi cấu thành từ tập tất phần tử chuỗi ban đầu xếp lại theo thứ tự tăng dần trị số phần tử Khi giá trị

nhỏ phần tửđầu tiên giá trị lớn phần tử cuối chuỗi trình tự Ta có chương trình dạng thủ tục sau

SUBROUTINE XMAXMIN (X,N, AMAX, AMIN) ! CT NAY TIM MAX, MIN CUA CHUOI X

! INPUT: + X MANG DO DAI N CHUA SO LIEU QUAN TRAC ! + N DUNG LUONG MAU

! OUTPUT:+ AMAX,AMIN lA MAX, MIN CUA X

(163)

! FUNCTION/SUBROUTINE DUOC GOI TOI: KHONG INTEGER N,I,J

REAL, INTENT(INOUT) :: X(N) ! Khi vào: Mảng chứa số liệu ban đầu

! Khi ra: Mảng xếp

REAL AMAX, AMIN, TMP DO I=1,N-1

K = I DO J=I+1,N

IF (X(J) < X(K)) K = J ENDDO

IF (K /= I) THEN TMP = X(K) X(K) = X(I) X(I) = TMP ENDIF

ENDDO AMAX = X(N) AMIN = X(1) RETURN

END SUBROUTINE

Chú ý chương trình này, vào mảng X số liệu ban đầu, trả chương trình gọi mảng X mảng mà phần tử xếp theo thứ tự tăng dần

9.1.4 Xác định phân vị chuỗi

Giả sử có chuỗi số liệu { x1, x2, , xn} Ký hiệu chuỗi trình tự chuỗi { x(1), x(2), , x(n)}

với x(1)≤x(2) ≤ ≤x(n) Khi đó, phân vị qp chuỗi ứng với xác suất p được xác định bởi: qp = x(F(x)=p) Khi p=0.5, phân vị q0.5được gọi trung vị xác định bởi:

⎪⎩ ⎪ ⎨ ⎧

+ =

= +

+

chẵn với

lẻ với

n x

x

n x

q Me

n n

n

2

) / ( ) / (

) / ) ((

0 (9.1.3)

Nếu p=0.25 ta gọi q0.25 phân vị p=0.75 q0.75được gọi phân vị Thực chất phân vị tương ứng trung vị nửa nửa chuỗi Chúng gọi tứ vị, chúng với trung vị chia chuỗi số liệu tương ứng thành bốn “đoạn” Chương trình dạng hàm Q05 sau tính trung vị chuỗi X độ dài N phần tử, cịn chương trình dạng thủ tục QUANTILES tính trung vị phân vị dưới, phân vị chuỗi FUNCTION Q05(X,N)

! HAM NAY TINH TRUNG VI CUA CHUOI X ! INPUT: + X LA MANG SO LIEU BAN DAU

! + N LA DO DAI CUA X (DUNG LUONG MAU) ! OUTPUT:+ TRUNG VI CUA CHUOI

(164)

REAL X(N), AMAX, AMIN INTEGER N,NC

CALL XMAXMIN (X,N, AMAX, AMIN) NC=N/2

IF (MOD(N,2)==0) THEN Q05=(X(NC)+X(NC+1))/2.0 ELSE

Q05=X(NC+1) ENDIF

RETURN

END FUNCTION !

SUBROUTINE QUANTILES(X,N,Q50,Q25,Q75)

! CT NAY TINH CAC PHAN VI CHINH CUA CHUOI X(N) ! INPUT: + X MANG CHUA CHUOI SO LIEU BAN DAU ! + N DUNG LUONG MAU

! OUTPUT: + TRUNG VI Q50

! + CAC PHAN VI DUOI VA TREN Q25, Q75 ! FUNCTION/SUBROUTINE DUOC GOI TOI: Q05(X,N) !

REAL X(N), X1(N)

INTEGER N,I,NC1,NC2,NT,J REAL Q50,Q25,Q75

Q50=Q05(X,N) NT=N

NC1=NT/2

IF (MOD(NT,2)==0) THEN NC2=NC1+1

ELSE

NC1=NC1+1 NC2=NC1 ENDIF DO I=1,NC1 X1(I)=X(I) ENDDO

Q25=Q05(X1,NC1) J=0

DO I=NC2,N J=J+1 X1(J)=X(I) ENDDO

Q75=Q05(X1,NC1) RETURN

END SUBROUTINE

9.1.5 Tính mômen phân bố

Giả sử chuỗi số liệu { x1, x2, , xn} kết quan trắc thực nghiệm biến ngẫu nhiên X Khi

(165)

− Mômen gốc bậc r: ar = ∑ = n t r t x n 1 1 (9.1.4)

− Mômen trung tâm bậc r: ∑

= − = n t r t

r x x

n m ) ( 1 (9.1.5)

Trong r một số nguyên dương Khi r=1 ta có a1=x m1=0 Khi r=2 ta có a2= ∑

= n t t x n 1 2 ~ ) ( 1 x x n t

t x D s

x n

m = ∑ − = =

=

, D~x phương sai thực nghiệm, sx độ lệch chuẩn Giữa mômen gốc mômen trung tâm liên hệ với qua công thức:

= −

− = r

k r k

k k r k

r C a a

m

0

) 1

( (9.1.6)

hay dạng cụ thể hơn:

( ) ∑ ∑ = = − − = r k n t k k r t k r k

r C x x

n m ) 1 ( 1 (9.1.7) Các chương trình sau tính mơmen gốc mơmen trung tâm chuỗi

FUNCTION AMMGOC(X,N,K) !

! HAM NAY TINH MOMEN GOC BAC K CUA CHUOI SO LIEU ! INPUT: + X MANG SO LIEU BAN DAU DO DAI N

! + N DUNG LUONG MAU ! + K BAC CUA MOMEN ! OUTPUT: MOMEN GOC BAC K ! REAL X(N) INTEGER N,K,I REAL TMP TMP=0.0 DO I=1,N TMP=TMP+X(I)**K ENDDO AMMGOC=TMP/REAL(N) RETURN END FUNCTION ! FUNCTION AMMTAM(X,N,K)

! HAM NAY TINH MOMEN TRUNG TAM BAC K CUA CHUOI X ! INPUT: + X MANG SO LIEU BAN DAU DO DAI N

! + N DUNG LUONG MAU ! + K BAC CUA MOMEN

(166)

! AMMGOC(X,N,K), COMBIN(N,K) REAL X(N)

INTEGER N,K,I REAL TMP,TB TB=AMMGOC(X,N,1) TMP=0

DO I=0,K

TMP=TMP+(-1)**I*COMBIN(K,I)*TB**I*AMMGOC(X,N,K-I) ENDDO

AMMTAM=TMP RETURN

END FUNCTION

Chương trình AMMTAM cần gọi chương trình tính tổ hợp chập k n Để tính tổ hợp chập ta lại cần phải tính giai thừa Do sau dẫn hai chương trình hàm tính tổ hợp chập tính giai thừa

FUNCTION COMBIN(N,K) ! TINH TO HOP CHAP K CUA N

! INPUT: + N >= K LA NHUNG SO NGUYEN ! OUTPUT: TO HOP CHAP K CUA N

! FUNCTION/SUBROUTINE DUOC GOI TOI: FAC(N) !

IF (N<0.OR.K<0.OR.N<K) THEN

WRITE(*,*)' INVALID NUMERIC INPUT ' STOP

ELSE

COMBIN=FAC(N)/FAC(K)/FAC(N-K) RETURN

ENDIF

END FUNCTION !

FUNCTION FAC(N) ! TINH N! (N GIAI THUA)

! INPUT: + N SO NGUYEN KHONG AM ! OUTPUT: + N!

!

REAL TMP IF (N.LT.0) THEN

WRITE(*,*)' INVALID NUMERIC INPUT IN FAC FUNC.' STOP

ELSE IF (N==0.OR.N==1) THEN FAC=1.0

RETURN ELSE TMP=1.0 DO I=2,N

TMP=TMP*REAL(I) ENDDO

(167)

RETURN ENDIF

END FUNCTION

9.1.6 Tính sốđặc trưng thống kê khác

Giả sử có chuỗi số liệu { x1, x2, , xn} Các đặc trưng thống kê chuỗi bao gồm: Trung bình số học, trung vị, trimean, trung bình hiệu chỉnh, phương sai độ lệch chuẩn, số biên độ phần tư, phương sai hiệu chỉnh, độ bất đối xứng, số Yull−Kendall Trong mục trước ta biết cách lập chương trình tính sốđặc trưng Các đặc trưng cịn lại tính theo cơng thức sau

− Hệ số bất đối xứng: A = 33

x s m

= 3

3 ) ( 1 x n t t s x x n∑=

(9.1.8)

− Trimean: Trimean=

4

2 0.5 0.75

25

0 q q

q + +

(9.1.9)

− Biên độ phần tư: IQR = q0.75 q0.25 (9.1.10) − Trung bình hiệu chỉnh: ∑

− + =

= n k

k i i x k n x ) ( 2 1

α (9.1.11)

− Phương sai hiệu chỉnh: ∑( )

− + =

− −

= n k

k i i x x k n s ) ( 2 1 α

α (9.1.12)

trong k, số ngun làm trịn tích αn, số thành phần bị cắt bỏ, tính từ hai đầu mút, chuỗi trình tự; α số phần trăm thành phần bị cắt bỏở đầu mút gọi bậc hiệu chỉnh; x(i) thành phần chuỗi trình tự

− Chỉ số Yule-Kendall:

( ) ( ) IQR q q q IQR q q q q

yk 0.75 0.5 0.5 0.25 0.25 0.5 0.75 + − = − − − =

γ (9.1.13)

Chương trình sau cho phép tính tất đặc trưng nói chuỗi { x1, x2, , xn}

SUBROUTINE ANOVA(X,N,ALFA,TB,MEDIAN,TRIMEAN,TBHC, & DX,SX,IQR, SHC,A,YULKED)

! CHUONG TRINH NAY TINH CAC DAC TRUNG TK DON GIAN ! INPUT: + X MANG SO LIEU BAN DAU DO DAI N

! + N DUNG LUONG MAU

! + ALFA (%) PHAN TRAM SO LIEU BI CAT BO ! OUTPUT: + TB: TRUNG BINH SO HOC

! + MEDIAN: TRUNG VI ! + TRIMEAN

(168)

! + DX: PHUONG SAI ! + SX: DO LECH CHUAN

! + IQR: CHI SO BIEN DO PHAN TU ! + SHC: PHUONG SAI HIEU CHINH ! + A: DO BAT DOI XUNG

! + YULKED: CHI SO YULE-KENDALL

! FUNCTION/SUBROUTINE DUOC GOI TOI: QUANTILES !

REAL X(N)

REAL ALFA,TB,MEDIAN,TRIMEAN,TBHC REAL DX,SX,IQR, SHC,A,YULKED

REAL Q50,Q25,Q75,TMP INTEGER N,I,N1,K !

TB=AMMGOC(X,N,1) DX=AMMTAM(X,N,2) SX=SQRT(DX)

A =AMMTAM(X,N,3)/(DX*SX)

CALL QUANTILES(X,N,Q50,Q25,Q75) MEDIAN=Q50

TRIMEAN=(Q25+2.0*Q50+Q75)/4.0 IQR=Q75-Q25

YULKED=(Q25-2.0*Q50+Q75)/IQR !

K=INT(REAL(N)*ALFA) TMP=0.0

DO I=K+1,N-K TMP=TMP+X(I) ENDDO

TBHC=TMP/REAL(N-2*K) !

TMP=0.0 DO I=K+1,N-K

TMP=TMP+(X(I)-TBHC)**2 ENDDO

SHC=TMP/REAL(N-2*K) RETURN

END SUBROUTINE

9.1.7 Tính mơmen tương quan hệ số tương quan

Khi xét đồng thời hai hay nhiều chuỗi số liệu, đặc trưng thống kê chuỗi, ta cần tính hệ số tương quan mômen tương quan cặp chuỗi Giả sử có cặp chuỗi số liệu { (x1,y1), (x2,y2), , (xn,yn)} Khi mơmen tương quan chúng có thểđược tính theo công thức:

( )( ) x y xy n

y y x x n

R n

t t t n

t

t t

xy = ∑ − − = ∑ −

=

=1

1 1

(169)

trong x, y tương ứng trung bình số học chuỗi {xt} {yt} Hệ số tương quan hai chuỗi sẽđược xác định bởi:

rxy = Rxy/(sxsy) (9.1.15)

với sx và sy tương ứng độ lệch chuẩn {xt} {yt}

Nếu xét đồng thời m chuỗi {xtj, t=1,2, ,n; j=1,2, ,m} ứng với cặp {xtj, xtk}, j,k=1,2, ,m sẽ có mơmen tương quan Tất mômen tương quan lập thành ma trận m hàng, m cột, gọi ma trận tương quan:

(Rjk) =

⎟ ⎟ ⎟ ⎠ ⎞ ⎜ ⎜ ⎜ ⎝ ⎛ mm m m R R R R 1 11 (9.1.16)

trong

k jx

x

jk R

R = mômen tương quan {xtj} {xtk}, tính theo cơng thức tương tự

đây Hệ số tương quan {xtj} {xtk} sẽđược xác định rjk=Rjk/sjsk, với sj=sxj, sk=sxk tương

ứng độ lệch chuẩn {xtj} {xtk} Các hệ số tương quan lập thành ma trận tương quan chuẩn hóa:

(rjk) =

⎟ ⎟ ⎟ ⎠ ⎞ ⎜ ⎜ ⎜ ⎝ ⎛ mm m m r r r r 1 11 (9.1.17)

Các chương trình sau cho phép tính mơmen tương quan ma trận tương quan chuỗi số liệu

FUNCTION HSTQ(X,Y,N)

!HAM NAY TINH HE SO TUONG QUAN GIUA HAI BIEN X VA Y ! INPUT: + X(N) MANG CHUA SO LIEU CUA X

! + Y(N) MANG CHUA SO LIEU CUA Y ! + N DUNG LUONG MAU

! OUTPUT: R: HE SO TUONG QUAN GIUA X VA Y ! CAC HAM DUOC GOI TOI: AVER, STDEV

(170)

END FUNCTION !

SUBROUTINE COVAR(X,N,M,R,TB)

! C/TRINH NAY TINH MA TRAN TUONG QUAN CUA M CHUOI ! INPUT: + X(N*M) MANG CHIEU CHUA S/LIEU BAN DAU ! LUU THEO COT CUA MA TRAN XX(N,M)

! (X(1,1), X(2,1), ,X(N,1),X(1,2), ) ! + N DUNG LUONG MAU

! + M SO BIEN

! OUTPUT:+ R(M*M) MANG MOT CHIEU ! CHUA MA TRAN TUONG QUAN

! + TB(M) MANG CHIEU (TRUNG BINH CAC BIEN) !

REAL X(N*M),XX(N,M),R(M*M),RR(M,M),TB(M) K=0

DO J=1,M

TB(J)=AVER(X((J1)*N+1,J*N),N) DO I=1,N

K=K+1 XX(I,J)=X(K) ENDDO

ENDDO DO J=1,M DO K=J,M RR(J,K)=0.0 DO I=1,N

RR(J,K)=RR(J,K)+(XX(I,J)-TB(J))*(XX(I,K)-TB(K)) ENDDO

RR(J,K)=RR(J,K)/REAL(N) IF (K /= J) RR(K,J)=RR(J,K) ENDDO

ENDDO L=0 DO K=1,M DO J=1,M L=L+1

R(L)=RR(J,K) ENDDO

ENDDO RETURN

END SUBROUTINE !

SUBROUTINE CORRE(X,N,M,R)

!CHUONG TRINH NAY TINH MA TRAN TUONG QUAN CHUAN HOA ! CUA TAP M BIEN TU SO LIEU BAN DAU CO DUNG LUONG N !INPUT:+ X MANG MOT CHIEU KICH THUOC N*M LUU TRU SO ! LIEU BAN DAU DANG MA TRAN N HANG M COT

(171)

! + M SO BIEN

! OUTPUT: + R(M*M) MANG MOT CHIEU LUU TRU MA TRAN ! TUONG QUAN CHUAN HOA CUA M BIEN

!

REAL X(N*M),XX(N,M),R(M*M),TB(M),SX(M) K=0

DO J=1,M

TB(J)=AVER(X((J1)*N+1,J*N),N) SX(J)=STDEV(X((J1)*N+1,J*N),N) DO I=1,N

K=K+1 XX(I,J)=X(K) ENDDO

ENDDO JK=0 DO J=1,M DO K=1,M JK=JK+1 R(JK)=0.0 DO I=1,N

R(JK)=R(JK)+XX(I,J)*XX(I,K) ENDDO

R(JK)=R(JK)/REAL(N)-TB(J)*TB(K) R(JK)=R(JK)/(SX(J)*SX(K))

ENDDO ENDDO RETURN

END SUBROUTINE

Chú ý hai chương trình COVAR CORRE đây, số liệu ban đầu hiểu lưu ma trận N hàng, M cột, phần tử mảng nhớđược Fortran lưu dạng vectơ, nên trước gọi chương trình ta cần chuyển chúng dạng mảng chiều Nếu không thực việc chuyển đổi này, kết tính tốn sai kích thước thực mảng vào từ chương trình gọi mảng khai báo chương trình khác Câu lệnh chuyển thực chương trình gọi là:

DO J=1,M

X((J-1)*N+1:J*10) = XX(1:N,J) ENDDO

Trong XX mảng hai chiều lưu số liệu M biến, với dung lượng mẫu N, cịn X mảng chiều kích thước NxM sẽđược truyền vào chương trình

Ta khắc phục nhược điểm cách sử dụng mảng động Ý tưởng chỗ, mảng

(172)

REAL, ALLOCATABLE :: A(:,:),B(:,:),C(:)

ALLOCATE (A(N,M),B(M,M),C(M))

CALL COVAR_1 (A, N, M, B, C)

CALL CORRE_1 (A, N, M, B)

Khi đó, chương trình COVAR CORRE tương ứng đổi thành COVAR_1 CORRE_1 sau đây:

SUBROUTINE COVAR_1(X,N,M,R,TB) !

!INPUT:+ X(N,M) MANG HAI CHIEU CHUA SO LIEU BAN DAU ! + N DUNG LUONG MAU

! + M SO BIEN

! OUTPUT:+ R(M,M) MANG HAI CHIEU ! CHUA MA TRAN TUONG QUAN

! + TB(M) MANG MOT CHIEU (TRUNG BINH CAC BIEN) !

REAL X(N,M), R(M,M),TB(M) DO J=1,M

TB(J)=AVER(X(:,J),N) ENDDO

DO J=1,M DO K=J,M R(J,K)=0.0 DO I=1,N

R(J,K)=R(J,K)+X(I,J)*(X(I,K) ENDDO

R(J,K)=R(J,K)/REAL(N)TB(J)*TB(K) R(K,J)=R(J,K)

ENDDO ENDDO RETURN

END SUBROUTINE !

SUBROUTINE CORRE_1(X,N,M,R) !

! INPUT: + X(N,M) MANG HAI CHIEU LUU TRU SO LIEU ! + N DUNG LUONG MAU

! + M SO BIEN

! OUTPUT: + R(M,M) MANG HAI CHIEU LUU TRU MA TRAN ! TUONG QUAN CHUAN HOA CUA M BIEN

!

REAL X(N,M), R(M,M),TB(M),SX(M) DO J=1,M

(173)

SX(J)=STDEV(X(:,J),N) ENDDO

DO J=1,M DO K=J,M

R(J,K)=HSTQ (X(:,J),X(:,K),N) R(K,J)=R(J,K)

ENDDO ENDDO RETURN

END SUBROUTINE

9.2 MỘT SỐ BÀI TOÁN VỀ MA TRẬN

9.2.1 Tích hai ma trận

Cho ma trận A(N,M) gồm N hàng, M cột ma trận B(M,P) gồm M hàng, P cột Ma trận tích hai ma trận có kích thước N hàng, P cột mà phần tử xác định hệ thức sau:

=

= M j ij jk

ik a b

c

(9.2.1) cik phần tử hàng i cột k ma trận C(N,P), aij bjk tương ứng phần tử hàng i cột j

và hàng j cột k ma trận A B

Với cơng thức ta có chương trình tính tích hai ma trận sau SUBROUTINE MULTIP(A,B,C,N,M,P)

! CHUONG TRINH NAY TINH TICH CUA HAI MA TRAN ! INPUT: + A(N*M) MANG MOT CHIEU (N HANG, M COT) ! LUU MA TRAN A THEO COT

! + B(M*P) MANG MOT CHIEU (M HANG, P COT) ! LUU MA TRAN B THEO COT

! + N SO HANG CUA MA TRAN A

! + M SO COT CUA A VA LA SO HANG CUA B ! + P SO COT CUA B

! OUTPUT: + C(N*P) MANG MOT CHIEU (N HANG, P COT) ! LUU MA TRAN C THEO COT

INTEGER N,M,P

REAL A(N*M),B(M*P),C(N*P) DO I=1,N

DO K=1,P IK=(K-1)*N+I C(IK)=0.0 DO J=1,M IJ=(J-1)*N+I JK=(K-1)*M+J

(174)

ENDDO ENDDO RETURN

END SUBROUTINE

Nếu sử dụng cách biểu diễn mảng hai chiều, chương trình MULTIP có thểđược viết lại thành: SUBROUTINE MULTIP_1(A,B,C,N,M,P)

! INPUT: + A(N,M) MANG MOT CHIEU (N HANG, M COT) ! + B(M,P) MANG MOT CHIEU (M HANG, P COT) ! + N SO HANG CUA MA TRAN A

! + M SO COT CUA A VA LA SO HANG CUA B ! + P SO COT CUA B

! OUTPUT: + C(N,P) MANG MOT CHIEU (N HANG, P COT) INTEGER N,M,P

REAL A(N,M),B(M,P),C(N,P) DO I=1,N

DO K=1,P C(I,K)=0.0 DO J=1,M

C(I,K)=C(I,K)+A(I,J)*B(J,K) ENDDO

ENDDO ENDDO RETURN

END SUBROUTINE

Nếu ma trận B gồm cột, B(M,1), tức B vectơ cột, chương trình cho phép nhân ma trận với vectơ

9.2.2 Định thức ma trận

Nếu A ma trận vuông gồm N hàng N cột định thức ma trận A số xác

định bởi:

nn n

n

n n

a a

a

a a

a

a a

a A D

det

2

2 22

21

1 12

11

=

= =∑±

n

nr r

ra a

a11 22 (9.2.2)

trong số r1, r2, , rn chạy qua tất n! hoán vị có số 1,2, ,n, cịn dấu số hạng (+) hay (−) tuỳ theo hoán vị tương ứng chẵn hay lẻ Số n gọi cấp định thức

Có nhiều thuật tốn để tính định thức A Bạn đọc tham khảo chẳng hạn [ ] Sau phương án tính

(175)

nn n n n n n a a a a a a a a a D 2 22 21 12 11 = = nn n n n n a a a a a a a a a 2 22 21 ) ( ) ( 12 11

với a(1j) a1j/a11,j 1,2, ,n

1 = =

Sử dụng phép biến đổi Gauss ta nhận được:

Dn=

nn n n n n a a a a a a a a a 2 22 21 ) ( ) ( 12 11 = ) ( ) ( ) ( ) ( 22 ) ( ) ( 12 11 nn n n n a a a a a a a = = ) ( ) ( ) ( ) ( 22 11 nn n n a a a a

a =a11Dn−1

Quá trình tiếp tục ta nhận hệ thức cuối cùng: (1) ( 1) 22 11 − = n nn a a a D

Dựa thuật tốn ta có chương trình tính FUNCTION DET(X,N)

! HAM NAY TINH DINH THUC CUA MA TRAN A(N,N)

!INPUT:+ X(N*N) MANG CHUA CAC PHAN TU CUA MA TRAN A ! LUU DANG COT: X(1)=A(1,1), X(2)=A(2,1), ,

! X(N)=A(N,1),X(N+1)=A(1,2), X(N+2)=A(2,2), ! + N KICH THUOC MA TRAN A

! OUTPUT: DINH THUC CUA A !

REAL, PARAMETER :: EP=1.0E-6 REAL X(N*N),A(N,N) K=0 DO J=1,N DO I=1,N K=K+1 A(I,J)=X(K) ENDDO ENDDO D=1.0 N1=N-1 DO K=1,N1 AM=0.0 DO I=K,N T=A(I,K)

(176)

AM=T J=I ENDIF ENDDO

IF (ABS(AM)<=EP) THEN DT=0.0

DET=DT RETURN ELSE

IF (J/=K) THEN D=-D

DO I=K,N T=A(J,I) A(J,I)=A(K,I) A(K,I)=T ENDDO ENDIF ENDIF M=K+1 DO I=M,N T=A(I,K)/AM DO J=M,N

A(I,J)=A(I,J)-T*A(K,J) ENDDO

ENDDO D=D*A(K,K) ENDDO DT=D*A(N,N) DET=DT RETURN

END FUNCTION

Trong chương trình ma trận đầu vào lưu dạng mảng chiều Nếu ma trận đầu vào lưu dạng mảng hai chiều ta cần thay đổi phần đầu chương trình để nhận

được chương trình khác tương đương: FUNCTION DET_1(A,N)

! HAM NAY TINH DINH THUC CUA MA TRAN A(N,N)

!INPUT:+ A(N,N) MANG CHUA CAC PHAN TU CUA MA TRAN A ! + N KICH THUOC MA TRAN A

! OUTPUT: DINH THUC CUA A !

REAL, PARAMETER :: EP=1.0E-6 REAL A(N,N)

D=1.0 N1=N-1

RETURN

(177)

9.2.3 Phần phụđại số

Phần phụđại số Dij của phần tử aij ma trận vuông A gồm N hàng, N cột, định thức ma trận A sau loại bỏ hàng i cột j nhân với (−1)i+j Chương trình sau đây cho phép tính phần phụđại số

FUNCTION PPDS(A,N,IR,JC)

! HAM NAY TINH PHAN PHU DAI SO CUA PHAN TU B(IR,JC) ! (HANG IR, COT JC) CUA MA TRAN B(N,N)

! MA CAC PHAN TU CUA NO DUOC LUU TRONG MANG A(N*N) ! THEO QUI CACH COT

! TRUOC DONG SAU

! INPUT: + MANG A(N*N) CHUA MA TRAN DAU VAO CUA B ! + N KICH THUOC CUA B

! + IR CHI SO HANG ! + JC CHI SO COT

! OUTPUT: PHAN PHU D/SO CUA PHAN TU HANG IR COT JC !

REAL A(N*N), B(N,N) K=0

DO J=1,N DO I=1,N K=K+1 B(I,J)=A(K) ENDDO ENDDO K=0 DO J=1,N

IF (J/=JC) THEN DO I=1,N

IF (I/=IR) THEN K=K+1

A(K)=B(I,J) ENDIF ENDDO ENDIF ENDDO

IF (MOD(IR+JC,2)==0) THEN PPDS=DET(A,N-1)

ELSE

PPDS=DET(A,N-1) ENDIF

RETURN

(178)

9.2.4 Ma trận nghịch đảo

Nếu A ma trận vuông không suy biến cấp NxN (định thức khác 0) ma trận nghịch đảo A, ký hiệu A−1, sẽđược xác định bởi hệ thức: A.A−1 = I, đó I ma trận đơn vị

Ký hiệu phần tử hàng i cột j ma trận A−1 aij(−1) ta có cơng thức tính sau:

D D

a ij

ij =

−1)

( , i,j=1,2, , n

trong D = detA định thức ma trận A, Dij phần phụđại số phần tử aij ma trận A Ta tính ma trận nghịch đảo A phương pháp khử Gauss sau Giả sử

⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = nn n n n n a a a a a a a a a A 2 22 21 12 11

Ta lập ma trận B cách ghép ma trận đơn vị có kích thước vào bên phải A: ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = 0 0 2 22 21 12 11 nn n n n n a a a a a a a a a B

Sau thực phép biến đổi thông thường đểđưa ma trận B dạng:

⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = ′ nn n n n n b b b b b b b b b B 0 0 2 22 21 12 11

Khi đó, nửa bên phải B’ nghịch đảo A:

⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = − nn n n n n b b b b b b b b b A 2 22 21 12 11

Sau hai chương trình tính ma trận nghịch đảo SUBROUTINE MINVERT(AA,N)

(179)

! + N SO HANG/COT CUA MA TRAN A ! OUTPUT: AA MA TRAN NGHICH DAO CUA A !

REAL AA(N*N), A(N,N) K=0

DO J=1,N DO I=1,N K=K+1 A(I,J)=AA(K) ENDDO

ENDDO M=N-1 DO I=1,N R=A(I,1) DO K=1,M

A(I,K)=A(I,K+1)/R ENDDO

A(I,N)=1.0/R DO J=1,N

IF (I/=J) THEN R=A(J,1) DO K=1,M

A(J,K)=A(J,K+1)-R*A(I,K) ENDDO

A(J,N)=-R*A(I,N) ENDIF

ENDDO ENDDO K=0 DO J=1,N DO I=1,N K=K+1 AA(K)=A(I,J) ENDDO

ENDDO RETURN

END SUBROUTINE !

SUBROUTINE NDMT_GAUS (A,N)

! INPUT: + A(N,N) MANG CHIEU CHUA A ! + N: KICH THUOC CUA A

! OUTPUT: A(N,N) MA TRAN NGHICH DAO CUA A REAL A(N,N), B(N,2*N), X(2*N)

integer i,j,k

REAL Tmp1, Tmp2

B = ! Khởi tạo B

B( 1:N, 1:N ) = A(1:N,1:N) ! Nửa đầu của B DO I = 1, N ! Đường chéo nửa sau của B B( I, N+I ) =

(180)

DO I = 1, N Tmp1 = B( I, I )

IF (Tmp1 == 0) THEN ! Đổi chỗ hàng

K = I +

DO WHILE (Tmp1 == AND K <= N) Tmp1 = B( K, I )

K = K + END DO

IF (Tmp1 == 0) THEN PRINT*, "EXIT Here" STOP ELSE X = B( I, 1:2*N ) K = K -

B( I, 1:2*N ) = B( K, 1:2*N ) B( K, 1:2*N ) = X END IF END IF

! Chuẩn hóa hàng I cho phần tử đường chéo

B( I, 1:2*N ) = B( I, 1:2*N ) / Tmp1 ! Khử đường chéo nửa đầu của B DO J = 1, N

IF (J /= I) THEN Tmp2 = B( J, I )

B( J, 1:2*N ) = B( J, 1:2*N ) & - B( I, 1:2*N ) * Tmp2 END IF

END DO END DO

! Nghịch đảo của A(1:N, 1:N) A = B( 1:N, N+1:2*N ) END SUBROUTINE

9.2.5 Giải hệ phương trình đại số tuyến tính

Trong mục ta tìm hiểu số phương pháp lập trình giải hệ phương trình đại số tuyến tính Giả sử có hệ phương trình:

⎪ ⎪ ⎩ ⎪ ⎪ ⎨ ⎧ = + + + = + + + = + + + n n nn n n n n n n b x a x a x a b x a x a x a b x a x a x a 2 1 2 22 21 1 12 11 (9.2.3)

(181)

⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ n n nn n n n n b b b x x x a a a a a a a a a 2 2 22 21 12 11 (9.2.4)

Hay dạng gọn hơn:

Ax = b (9.2.5) đó:

A = ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ nn n n n n a a a a a a a a a 2 22 21 12 11

, x = ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ n x x x

, b = ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ n b b b (9.2.6)

Nếu A ma trận khơng suy biến, nghiệm hệ có thểđược xác định phương pháp sau: a Phương pháp nghịch đảo ma trận

x = A1b (9.2.7)

với A−1 ma trận nghịch đảo của A b Phương pháp Cramer

D D

x i

i = , i=1,2, ,n (9.2.8)

trong đó:

D = nn n n n n a a a a a a a a a 2 22 21 12 11 (9.2.9)

là định thức ma trận A,

nn i n n n i n i i n n n i i i a a b a a b a a b a a a a a a a a a D , , 2 1 , 1 , 1 , 22 21 , 12 11 + + + − − −

= (9.2.10)

là định thức ma trận A sau thay cột thứ i vectơ vế phải b c Phương pháp khử Gauss

(182)

⎪ ⎪ ⎩ ⎪ ⎪ ⎨ ⎧ ′ = ′ ′ = ′ + + ′ ′ = ′ + + ′ + ′ n n nn n n n n b x a b x a x a b x a x a x a 2 22 1 12 11

Khi nghiệm hệ sẽđược xác định hệ thức:

nn n n a b x ′ ′ = , 1 1 1 − − − − − − − ′ ′ ′ ′ − ′ = ′ ′ − ′ = n nn n n n n n n n n a a b a b a x a b x , , 11 1 a x a b x n j j j n ′ ′ − ′ = ∑=

Nếu hệ (9.2.3) đưa dạng “đường chéo” ta có:

⎪ ⎪ ⎩ ⎪ ⎪ ⎨ ⎧ ′′ = + + + ′′ = + + + ′′ = + + + n n n n b x x x b x x x b x x x 0 0 2 1

Trong trường hợp này, nghiệm hệđơn giản là:

1

1 b

x = ′′, x2 =b2′′, , xn =bn′′

Sau ba chương trình giải hệ phương trình đại số tuyến tính (9.2.3) tương ứng với ba phương pháp trình bày

SUBROUTINE GIAIHE_ND(A,B,X,N)

! CHUONG TRINH NAY GIAI HE PHUONG TRINH DSTT Ax=b ! BANG PP NGHICH DAO MA TRAN

!

!INPUT:+ A(N*N) MANG MOT CHIEU CHUA MA TRAN HE SO A ! (LUU THEO COT)

! + B(N) VECTO HE SO b ! + N SO PHUONG TRINH ! OUTPUT: + X(N) VECTO NGHIEM !

REAL A(N*N),B(N), X(N) CALL MINVERT(A,N) CALL MULTIP(A,B,X,N,N,1) RETURN END SUBROUTINE ! SUBROUTINE GIAIHE_CRM(A,B,X,N)

! CHUONG TRINH NAY GIAI HE PHUONG TRINH DSTT Ax=b ! BANG PP CRAMER

!

!INPUT:+ A(N*N) MANG MOT CHIEU CHUA MA TRAN HE SO A ! (LUU THEO COT)

(183)

! OUTPUT: + X(N) VECTO NGHIEM !

REAL A(N*N),B(N),X(N), AA(N*N) REAL D, DI

D = DET(A,N) DO I = 1,N AA(:)=A(:)

AA((I-1)*N+1:I*N) = B(:) DI = DET(AA,N)

X(I) = DI/D ENDDO RETURN

END SUBROUTINE !

SUBROUTINE GIAIHE_GAUSE (AA,B,X,N) integer N,i,j,k

REAL AA(N*N), B(N), X(N), A(N, N+1) DO I=1,N

A(:,I) = AA((I-1)*N+1:I*N) ENDDO

A(:,N+1) = B(:) DO I=1,N

Tmp = A( I, I ) ! Sắp xếp lại để A (I,I) <> IF (Tmp == 0) THEN

K = I +

DO WHILE (Tmp == AND K < N) Tmp = A( K, I )

K = K + END DO

IF (Tmp == 0) THEN PRINT*, "EXIT Here" STOP ELSE X = A( I, 1:N+1 ) K = K -

A( I, 1:N+1 ) = A( K, 1:N+1 ) A( K, 1:N+1 ) = X

END IF END IF

Tmp = A(i,i) ! Chuẩn hóa hàng I A(i,1:N+1) = A(i,1:N+1) / Tmp

i1=1,N ! Khử phần tử đường chéo

if (i1 /= i) then Tmp = A(i1,i)

A(i1,1:N+1)=A(i1,1:N+1)-A(i,1:N+1)*Tmp endif

enddo Enddo

(184)

END SUBROUTINE

9.3 TƯƠNG QUAN VÀ HỒI QUI TUYẾN TÍNH

9.3.1 Xây dựng phương trình hồi qui tuyến tính

Đây toán phổ biến ứng dụng nhiều thực tế Nội dung tốn phát biểu sau Giả sử {xt1,xt2, ,xtm; t=1,2, ,n} tập số liệu quan trắc thực nghiệm m biến ngẫu nhiên X1, X2, , Xm Xét mối quan hệ tương quan biến X1 (biến phụ thuộc) với tập m−1 biến lại (các biến độc lập) Hãy xây dựng phương trình hồi qui tuyến tính biến phụ thuộc X1 với tập biến độc lập X2, X3, , Xm

Với yêu cầu toán, ta cần xác định hệ số a1, a2, , am phương trình hồi qui: m mx a x a a

x1 = 1+ 2 2+ +

) (9.3.1)

Về lý thuyết xây dựng phương trình (9.3.1) bạn đọc tham khảo, chẳng hạn, [4] Sau

đây dẫn cơng thức tính hệ số aj, j=1,2, ,m một sốđại lượng liên quan đến việc phân tích phương sai đánh giá chất lượng phương trình hồi qui

Hệ số a1 (9.3.1) tính theo cơng thức: ∑ = − = m j j jx a x a

1 (9.3.2)

Trong ∑

=

= n

t tj

j n x

x

1

1

trung bình số học biến Xj, j=1,2,

Các hệ số a2, a3, , am xác định việc giải hệ phương trình đại số tuyến tính m−1 phương trình, m−1 ẩn số sau:

j m

k

k

jka R

R 1

2

=

=

, j=2,3, , m (9.3.3) Hay viết dạng ma trận:

⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ m m mm m m m m R R R a a a R R R R R R R R R 13 12 3 33 32 23 22 (9.3.3’)

Trong Rjk, j,k=2,3, ,m mômen tương quan biến Xj Xk, tính theo cơng thức:

( )( ) ∑ = − − = n t k tk j tj

jk n x x x x

R

1

1

(185)

( )( ) ∑ = − − = n t j tj t

j n x x x x

R 1 1 1 (9.3.5) Tổng bình phương biến sai hồi qui (U) biến sai thặng dư (Q) sai số chuẩn (s) ước lượng theo phương trình hồi qui (9.3.1) tính theo cơng thức:

( ) ∑ = − = n t t x x U 1

ˆ (9.3.6)

( ) ∑ = − = n t t t x x Q

1 ˆ (9.3.7)

m n

Q s

= (9.3.8)

với xˆt1 =a1+a2xt2+ +amxtm, t=1,2, , n ước lượng quan trắc xt1 theo phương trình hồi qui (9.3.1)

Trên sởđó ta có chương trình tính sau SUBROUTINE REGRE(X,N,M,A,S,Q,U,RR,F)

! CHUONG TRINH TINH CAC HE SO HOI QUI CUA P/TRINH ! HOI QUI GIUA X1 VA CAC X2, ,XM

! VA XAC DINH CAC DAI LUONG CHO PHAN TICH P/SAI ! DANG PHUONG TRINH HQ: X1=A1+A2*X2+ +AM*XM !

! INPUT: + X(N*M) MANG MOT CHIEU LUU SO LIEU ! QUAN TRAC CUA CAC X1 XM (LUU THEO COT) ! + N DUNG LUONG MAU

! + M SO BIEN (1 BIEN P.THUOC VA M-1 BIEN DLAP) ! + A MANG MOT CHIEU KICH THUOC M LUU CAC HE SO ! A1, A2, , AM

! + S SAI SO CHUAN (CHUAN SAI THANG DU)

! + Q TONG BINH PHUONG CAC BIEN SAI THANG DU ! + U TONG BINH PHUONG CAC BIEN SAI HOI QUI ! + RR HE SO TUONG QUAN BOI

! + F BIEN CO PHAN BO FISHER ! REAL X(N*M),A(M) REAL R(M*M),RXX(M*M),RY(M),TB(M),RX(M*M) CALL COVAR(X,N,M,R,TB) L=0 J=0 DO I=M+1,M*M

IF (MOD(I,M)/=1) THEN L=L+1

RXX(L)=R(I) ELSE

(186)

RY(J)=R(I) ENDIF ENDDO RX=RXX

CALL MINVERT(RX,M-1)

CALL MULTIP(RX,RY,A,M-1,M-1,1) TMP=0.0

DO J=1,M-1

TMP=TMP+A(J)*TB(J+1) ENDDO

TMP=TB(1)-TMP DO J=M,2,-1 A(J)=A(J-1) ENDDO A(1)=TMP RX=R

D=DET(RX,M) RX=R

D11=PPDS(RX,M,1,1) TMP=D/D11

RR=SQRT(1-TMP/R(1)) Q=0.0

DO I=1,N YHQ=0.0 DO J=2,M IJ=(J-1)*N+I

YHQ=YHQ+A(J)*X(IJ) ENDDO

YHQ=YHQ+A(1) TMP=X(I)-YHQ Q=Q+TMP*TMP ENDDO

U=REAL(N)*R(1)-Q

F=U*REAL(N-M)/(Q*REAL(M-1)) S=SQRT(Q/REAL(N-M))

RETURN

END SUBROUTINE

9.3.2 Tính hệ số tương quan riêng

(187)

m mx a x

a

x1 = 3 3+ +

) (9.3.9)

m mx b x

b

x2 = 3 3+ +

) (9.3.10)

Ký hiệu q1 q2 tương ứng thặng dư X1 X2đối với biến X3, , Xm, ta có:

1

1 x xˆ

q = − , q2 =x2 −xˆ2 (9.3.11)

Khi hệ số tương quan riêng r12.34 m X1 X2 biến X3, , Xm hệ số tương quan q1 q2, xác định hệ thức:

22 11 12 34 12 D D D

r m=− (9.3.12)

Trong D12, D11, D22 tương ứng phần phụđại số phần tử R12, R11, R22 ma trận tương quan mà phần tử mơmen tương quan Xj Xk, j,k=1,2, ,m:

( )( ) ∑ = − − = n

t tj j tk k

jk n x x x x

R

1

1

, j,k=1,2, ,m (9.3.13)

( ) ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = mm m m m m jk R R R R R R R R R R 2 22 21 12 11 (9.3.13’)

Một cách tổng quát, hệ số tương quan riêng rjk.12 m Xj Xkđối với biến X1, , Xm lại xác định bởi:

kk jj jk m k k j j jk D D D

r .12 −1,+1 −1,+1 =− , j,k=1,2, ,m (9.3.14)

Sau chương trình tính hệ số tương quan riêng hai biến biến lại số m biến xét

FUNCTION HSTQR(X,N,M,J,K)

! HAM NAY TINH HE SO TQUAN RIENG GIUA BIEN XJ VA XK ! KHI XET DONG THOI M BIEN X1,X2, ,XM

! INPUT: + X(N*M) MANG MOT CHIEU CHUA ! SO LIEU CAC BIEN

! + N DUNG LUONG MAU ! + M SO BIEN DUOC XET

! + J,K CHI SO BIEN DUOC TINH ! TUONG QUAN RIENG

(188)

REAL X(N*M), R(M*M), RT(M*M), TB(M) CALL COVAR(X,N,M,R,TB) RT=R RJK=PPDS(RT,M,J,K) RT=R RJJ=PPDS(RT,M,J,J) RT=R RKK=PPDS(RT,M,K,K) HSTQR=-RJK/(SQRT(RJJ*RKK)) RETURN END FUNCTION

9.3.3 Tính hệ số tương quan bội

Giả sử {xt1,xt2, ,xtm; t=1,2, ,n} tập số liệu quan trắc thực nghiệm m biến ngẫu nhiên X1, X2, , Xm Tương quan X1 với tập biến lại X2, X3, , Xmđược gọi tương quan bội Khi hệ số tương quan bội X1đối với biến X2, X3, , Xm hệ số tương quan xˆ1 x1, xác định bởi:

11 11 234 1 D R D

r m= − (9.3.15)

Trong D định thức ma trận tương quan

( ) ⎟⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜⎜ ⎜ ⎜ ⎜ ⎝ ⎛ = mm m m m m jk R R R R R R R R R R 2 22 21 12 11 (9.3.16)

và D11 phần phụđại số phần tử R11 Sau chương trình tính FUNCTION HSTQB(R,M,J)

! HAM TINH HE SO TQUAN BOI GIUA BIEN XJ VA TAP HOP ! M-1 BIEN X1,X2,X(J-1),X(J+1), ,XM

! INPUT: + X(N*M) MANG CHIEU CHUA S/LIEU CAC BIEN ! + N DUNG LUON MAU

! + M SO BIEN DUOC XET

! + J CHI SO BIEN DUOC TINH T/QUAN VOI TAP ! M-1 BIEN CON LAI

! OUTPUT: HE SO TQUAN BOI GIUA BIEN THU J VA M1 ! BIEN KHAC

!

REAL X(N*M), R(M*M), RT(M*M), TB(M) CALL COVAR(X,N,M,R,TB)

(189)

RJJ=PPDS(RT,M,J,J) RT=R

RR=DET(RT,M)

HSTQB=SQRT(1-RR/RJJ) RETURN

END FUNCTION 9.4 PHƯƠNG PHÁP SỐ

9.4.1 Tìm nghiệm phương trình

Trong mục ta đề cập đến việc lập chương trình tìm nghiệm phương trình F(x) = Nghiệm phương trình giá trịx0 mà F(x0) = Nếu F(x) một hàm đơn giản ta giải tìm nghiệm (x0) Nếu F(x) hàm phức tạp, việc tìm nghiệm gặp nhiều khó khăn, chí khơng tìm phương pháp giải tích Trong trường hợp ta tìm nghiệm gần phương trình cách lập chương trình cho máy tính Ở ví dụ 4.3 ta xét phương pháp lặp Newton để tìm nghiệm gần phương trình, cần phải biết đạo hàm hàm F(x) Tuy nhiên, nhiều trường hợp, việc tính đạo hàm hàm F(x) phức tạp, nên người ta thường sử dụng phương pháp chia đơi Nói chung, dù sử dụng phương pháp nào, việc tìm nghiệm phương trình F(x)=0 phương pháp số gắn liền với hội tụ

nghiệm Thời gian tính máy lúc phụ thuộc vào tốc độ hội tụ phương pháp Ví dụ phương pháp lặp Newton cho thời gian tính so với phương pháp chia đơi, tốc độ hội tụ nhanh Điều kiện hội tụ có thểđược xác định tiêu sau:

a) F(xi) <Epsilon (9.4.1)

b) xix0 <Epsilon (9.4.2)

c) xixi−1 <Epsilon (9.4.3)

Trong Epsilon số dương vơ bé tùy ý, x0 nghiệm xác phương trình, xi giá trị lấy làm xấp xỉ nghiệm Ta thấy, tiêu a) quan tâm đến độ xác hàm, tức xiđược lấy làm nghiệm gần làm cho giá trị hàm đủ nhỏ; tiêu b) xem xi nghiệm gần gần với nghiệm thực; tiêu c) lấy xi làm nghiệm gần gần với giá trị xấp xỉở bước trước Rõ ràng ta khơng hy vọng tìm nghiệm xác phương trình, trình lặp để tìm nghiệm kết thúc tiêu hội tụ thỏa mãn Ta chưa biết trước nghiệm xác x0 nên tiêu b) nói chung khơng sử dụng thực tế Sau

đây ta xét phương pháp chia đơi tìm nghiệm phương trình F(x)=0 sử dụng tiêu a) c) Về nguyên tắc, để tìm nghiệm phương trình F(x)=0, trước hết ta nên khảo sát sơ bộđể xác

định số nghiệm phương trình, khoảng giá trị x mà nghiệm nằm khoảng

(190)

bằng cách xác định dấu F(XL).F(XC) F(XC).F(XR) Quá trình tiến hành thỏa mãn tiêu hội tụ nghiệm

SUBROUTINE NGHIEM_CHIA_DOI (XL, XR,EPSILON,X0, ERROR) !Chuong trinh tim nghiem PT f(x)=0

! INPUT: + XL,XR: Khoang chua nghiem (neu có) ! + EPSILON: Do chinh xac

! OUTPUT: + X0: Nghiem phuong trinh (neu co) ! + ERROR=.FALSE neu có nghiem, ! =.TRUE neu khong co nghiem LOGICAL ERROR

REAL XL,XR,X0,EPSILON REAL SS,FXL,FXR,FX0

ERROR = FALSE ! Có nghiệm khoảng (XL,XR) IF (FF(XL)==0.) THEN ! Nghiệm đầu mút trái

X0 = XL RETURN

ELSE IF(FF(XR)==0.) THEN ! Nghiệm đầu mút phải

X0 = XR RETURN

ELSE IF(XL==XR) THEN ! Hai đầu mút trùng

ERROR = TRUE ! không phải nghiệm

RETURN

ELSE IF(XL>XR) THEN ! Đổi vị trí hai đầu mút

SS = XL XL = XR XR = SS END IF

SS = 999 ! Khởi tạo SS cho vòng lặp WHILE DO WHILE (SS >= EPSILON)

X0 = (XR+XL)/2 ! Điểm khoảng

FX0=FF(X0) FXL=FF(XL) FXR=FF(XR)

IF (FX0 == 0) THEN ! Nghiệm tại X0 EXIT

ELSE IF (FXL*FX0 < 0) THEN ! Nghiệm nửa bên trái

XR = X0

ELSE IF (FXR*FX0 < 0) THEN ! Nghiệm nửa bên phải

XL = X0 END IF

SS = ABS(XR-XL) ! Chỉ tiêu hội tụ nghiệm là c) ENDDO

CONTAINS

FUNCTION FF(X) REAL X

! Định nghĩa hàm F(X) ởđây !!! FF = X*X-5.*X+6

(191)

Trong chương trình trên, muốn sử dụng tiêu a) ta cần thay câu lệnh gán để tính SS câu lệnh

SS = ABS(FXR-FXL)

9.4.2 Tính tích phân xác định

Trong mục ta xét phương pháp lập trình tính tích phân xác định:

∫ =b a dx x f

I ( ) (9.4.4)

Ở ví dụ 4.2, mục 4.5 ta khảo sát cách tính tích phân phương pháp hình thang Tuy nhiên cách tính chưa hiệu Bạn đọc sửa đổi chương trình theo thuật toán sau đây, chạy so sánh kết với chương trình ví dụ 4.2 Cũng nhưở ví dụ 4.2, để tính tích phân ta tiến hành chia đoạn (a,b) thành N khoảng điểm chia xi, i=0,2, , N Khi đó, x0=a, x1, x2, , xN1, xn=b Ký hiệu độ dài khoảng chia Δx, ta có Δx = (b−a)/N Tích phân I được xấp xỉ tổng diện tích hình thang giới hạn trục hoành, đường f(x) đường thẳng x=xi

( ) ( ) ( )

[ ( ) ( ) ( ) ( ) ( ) ( )]

2 )

( 0 1 1 2 N 1 N

b a x f x f x f x f x f x f x dx x f

I =∫ ≈ Δ + + + + + − +

= ⎟ ⎠ ⎞ ⎜ ⎝ ⎛ + + Δ ∑− = 1 ) ( 2 ) ( ) ( 2 N i i x f b f a f x (9.4.5)

Khác với phương pháp hình thang, phương pháp Simpson chia đoạn (a,b) thành 2N khoảng nhau, thay cho việc nối điểm f(xi) liên tiếp đoạn thẳng phương pháp hình thang, ta xấp xỉ ba điểm liên tiếp đường parabol Ký hiệu điểm chia xi, i=0,1,2, , 2N, (x0=a, x1, x2, , x2N-1, x2N=b), độ dài khoảng chia Δx = (b−a)/2N Khi đó:

⎥ ⎦ ⎤ ⎢ ⎣ ⎡ + + + Δ ≈ =∫ ∑ ∑ = − − = N i i N i i b a x f x f b f a f x dx x f I 1 1

2 ) ( )

( ) ( ) ( )

( (9.4.6)

Sau chương trình tính tích phân xác định (9.4.4) theo phương pháp Simpson viết dạng chương trình hàm

FUNCTION SIMPSON (A, B, EP)

! Tinh tich phan xac dinh cua ham f(x) tu A den B ! INPUT: + A, B: Can duoi va can tren cua tich phan ! + EP: Do chinh xac

! OUTPUT: Gia tri cua tich phan REAL A,B,DX,S1,S2,SS, EP INTEGER N, I

(192)

DO

N = N +

DX = (B - A)/(2*N) S2 =

DO I = 1, N-1

S2 = S2 + FF(A + 2*I*DX) END DO

SS = DO I = 1, N

SS = SS + FF(A + (2*I-1)*DX) END DO

S2 = DX/3*(FF(A) + FF(B) + 2*S2 + 4*SS) SS = ABS ((S2-S1)/S2)

IF (SS < EP) EXIT S1 = S2

END DO SIMPSON = S2 CONTAINS

FUNCTION FF(X) REAL X

! DINH NGHIA HAM F(X) O DAY !!!

FF = 1/SQRT(8*ATAN(1.))*EXP(0.5*X*X) END FUNCTION

END FUNCTION

9.4.3 Sai phân hữu hạn đạo hàm

Giả sử giá trị hàm u(x) biết điểm rời rạc cách khoảng Δx Khi đạo hàm u(x) nhận sử dụng sai phân hữu hạn Thật vậy, khai triển Taylor hàm u(x) lân cận x ta được:

u(x+Δx)=u(x)+ ! ! ! 2 n x dx u d x dx u d x dx du n x n n x x Δ + + Δ + Δ (9.4.7)

u(x−Δx)=u(x)− ! ) ( ! ! 2 n x dx u d x dx u d x dx du n x n n n x x Δ − + + Δ + Δ (9.4.8)

Từ hệ thức ta nhận cơng thức tính đạo hàm hàm u(x) sau: 1) Đạo hàm bậc nhất:

(193)

! 2 ) ( ) ( ) ( 2 + Δ + Δ Δ − − = x dx x u d x x x u x u dx du x (9.4.10) ! 3 ) ( 2 2 ) ( ) ( 3 + Δ + Δ Δ − − Δ + = x dx x u d x x x u x x u dx du x (9.4.11) Hay viết dạng khác bỏ qua hạng bậc cao:

) ( ) ( ) ( x x x u x x u dx du x Δ + Δ − Δ +

= ε (9.4.9’)

) ( ) ( ) ( x x x x u x u dx du x Δ + Δ Δ − −

= ε (9.4.10’)

2 ) ( ) ( ) ( x x x x u x x u dx du x Δ + Δ Δ − − Δ +

= ε (9.4.11’)

trong ε(Δx) ε(Δx2) tương ứng biểu thị sai số xác định đạo hàm gọi sai số bậc sai số bậc hai Các công thức (9.4.9’), (9.4.10’) gọi đạo hàm có độ xác bậc nhất, cịn (9.4.11’) có độ xác bậc hai Ba cơng thức tương ứng gọi sơđồ sai phân tiến, sai phân lùi sai phân trung tâm

Như vậy, để tính đạo hàm bậc u(x) x theo (9.4.9’) và(9.4.10’) ta cần biết giá trị hàm x điểm lân cận trước sau x, để tính theo (9.4.11’) ta cần biết hai

điểm lân cận trước sau x

Tương tự, cách khai triển Taylor hàm u(x) bốn điểm lân cận ta nhận cơng thức tính đạo hàm bậc u(x) với độ xác bậc bốn:

x dx du = ⎥⎦ ⎤ ⎢⎣ ⎡ Δ Δ − − Δ + − ⎥⎦ ⎤ ⎢⎣ ⎡ Δ Δ − − Δ + x x x u x x u x x x u x x u 4 ) 2 ( ) 2 ( 3 1 2 ) ( ) ( 3 4 (9.4.12) 2) Đạo hàm bậc hai:

Các cơng thức tính đạo hàm bậc hai u(x) nhận cách khai triển thành chuỗi Taylor hàm u(x) lân cận x Tùy theo cách biểu diễn, ta có cơng thức tính với độ

chính xác khác Sau hai cơng thức thương dùng:

−Độ xác bậc hai:

x dx u d 2

= ( ) ( ) 2 ( ) ( 2)

2 x x x u x x u x x

u + Δ

Δ − Δ − − Δ + ε (9.4.13)

(194)

[ ]

[ ]

2 2 ) ( ) 2 ( ) 2 ( 12 1 ) ( ) ( 3 4 ) ( 5 1 1 x x x u x x u x x u x x u x u x dx u d Δ + ⎥⎦ ⎤ Δ − − Δ + − − ⎢⎣ ⎡− + +Δ − −Δ Δ = ε (9.4.14)

Sau hai chương trình tính đạo hàm bậc bậc hai hàm u(x) cho n điểm cách

đều Trong chương trình tính đạo hàm bậc nhất, tham số SODO cho phép lựa chọn bốn sơđồđã trình bày với độ xác khác Ngồi ra, chương trình cịn đưa vào tùy chọn CYC cho điều kiện biên tuần hồn khơng tuần hồn

SUBROUTINE DH1(U,UX,N,DX,SODO,CYC)

! CHUONG TRINH TINH DAO HAM BAC NHAT CUA HAM U(X) ! INPUT: + U(N) MANG CHIEU CHUA GIA TRI CUA U(X) ! + N: SO DIEM CO GIA TRI CUA U(X)

! + DX: DO DAI KHOANG CHIA CUA X ! + SODO: =1 SAI PHAN TIEN

! =2 SAI PHAN LUI

! =3 SAI PHAN TRUNG TAM DCX=2 ! =4 SAI PHAN TRUNG TAM DCX=4 ! + CYC: = TRUE NEU BIEN TUAN HOAN ! = FALSE NEU BIEN KHONG TUAN HOAN ! OUTPUT: UX: DAO HAM CUA U(X)

! SODO=1,CYC=.FALSE.: UX(1:N-1) ! SODO=2,CYC=.FALSE.: UX(2:N) ! SODO=3,CYC=.FALSE.: UX(2:N-1) ! CYC=.TRUE.: UX(1:N)

!

INTEGER N,SODO, N1,N2,N3 LOGICAL CYC

REAL U(N),UX(N),C1,C2,DX2,DX4 SELECT CASE (SODO)

CASE (1) DO I=1,N-1

UX(I) = (U(I+1)-U(I))/DX ENDDO

IF (CYC) UX(N) = UX(1) CASE (2)

DO I=2,N

UX(I) = (U(I)-U(I-1))/DX ENDDO

IF (CYC) UX(1) = UX(N) CASE (3)

DX2=2*DX DO I=2,N-1

UX(I) = (U(I+1)-U(I-1))/DX2 ENDDO

(195)

IF (CYC) THEN

UX(1) = (U(2)-U(N-1))/(2*DX) UX(N) = UX(1)

END IF CASE (4) N1 = N-1 N2 = N-2 N3 = N-3 C1 = 4./3 C2 = 1./3

DX2 = 1./(2.*DX) DX4 = 1./(4.*DX) DO I = 3, N2

UX(I) = C1*((U(I+1)-U(I-1))*DX2) & -C2*((U(I+2)-U(I-2))*DX4) ENDDO

IF (CYC) THEN

UX(2) = C1*((U(3)-U(1))*DX2)-C2 & *((U(4)-U(N-1))*DX4)

UX(1) = C1*((U(2)-U(N-1))*DX2)-C2 & *((U(3)-U(N-2))*DX4)

UX(N) = UX(1)

UX(N-1)= C1*((U(N)-U(N-2))*DX2)-C2 & *((U(2)-U(N-3))*DX4)

END IF

END SELECT END SUBROUTINE

! - !

SUBROUTINE DH2 (U,UX,N,DX,SODO)

! CHUONG TRINH TINH DAO HAM BAC HAI CUA HAM U(X) ! INPUT: + U(N) MANG CHIEU CHUA GIA TRI CUA U(X) ! + N: SO DIEM CO GIA TRI CUA U(X)

! + DX: DO DAI KHOANG CHIA CUA X ! + SODO: =1 DO CHINH XAC BAC ! =2 DO CHINH XAC BAC ! OUTPUT: UX: DAO HAM CUA U(X) ! SODO=1: UX(2:N-1)

! SODO=2: UX(3:N-2) INTEGER N,SODO

REAL U(N),UX(N), DX REAL DX2,C15,C43,C12 DX2=DX*DX

SELECT CASE (SODO) CASE (1)

DO I=2,N-1

UX(I) = (U(I+1)-U(I-1)-2.*U(I))/DX2 ENDDO

(196)

C15=1./5 C43=4./3 C12=1./12 DO I=3,N-2 UX(I)=(-C15*U(I)+C43*(U(I+1)-U(I-1)) & -C12*(U(I+2)-U(I-2)))/DX2 ENDDO END SELECT END SUBROUTINE !

9.4.4 Toán tử Laplaxian

Giả sử u(x,y) hàm hai biến x y Khi hệ thức:

u y u x u y x u 2 2

2 ( , ) ≡∇

∂ ∂ + ∂ ∂ =

∇ (9.4.15)

được gọi Laplaxian hàm u(x,y) Đây toán tửđược dùng phổ biến số lĩnh vực

Để xác định toán tử này, hàm u(x,y) thường cho hệ thống lưới điều hòa biến x y: uij = u(xi,yj), đó (xi,yj) điểm nút lưới Giả thiết khoảng cách nút lưới không đổi h theo chiều x y Khi đó, phép khai triển Taylor lân cận điểm (x,y) thực phép biến đổi đơn giản ta nhận cơng thức tính Laplaxian u(x,y) sau đây:

1) Sơđồ điểm, độ xác bậc hai:

[ ] ( ) ) , ( ( ) , ( ) , ( ) , ( ) , ( 2 h y x u y h x u h y x u y h x u h y x u h u ε + − + + − + − + + = ∇ (9.4.16)

2) Sơđồ điểm, độ xác bậc hai:

{ }

[4 4 ( , ) ( , ) ( , ) ( , )

6 1

2

2 u x h y u x h y u x y h u x y h

h

u= + + − + + + −

∇ + { }] ( ) ) , ( 20 ) , ( ) , ( ) , ( ) , ( h y x u h y h x u h y h x u h y h x u h y h x u ε + − − − + + − + + + − + + + + (9.4.17) Chương trình tính tốn tử Laplaxian theo sơđồ trình bày SUBROUTINE LAPLA52 (U,LAPU,H,N,M)

! CHUONG TRINH TINH LAPLAXIAN CUA U(X,Y) ! THEO SO DO DIEM, DO CHINH XAC BAC ! INPUT: + U(N,M) GIA TRI CUA U

! + N,M SO DIEM NUT THEO X VA Y

(197)

REAL U(N,M),LAPU(N,M),H INTEGER IP1, IM1, JP1, JM1 N1=N-1

M1=M-1 DO I=2,N1 DO J=2,M1 IP1=I+1 IM1=I-1 JP1=J+1 JM1=J-1

LAPU(I,J)=(U(IP1,J)+U(IM1,J)+U(I,JP1) & +U(I,JM1)-4.*U(I,J))/H**2

ENDDO ENDDO RETURN

END SUBROUTINE

! -

SUBROUTINE LAPLA92 (U,LAPU,H,N,M)

! CHUONG TRINH TINH LAPLAXIAN CUA U(X,Y) ! THEO SO DO DIEM, DO CHINH XAC BAC ! INPUT: + U(N,M) GIA TRI CUA U

! + N,M SO DIEM NUT THEO X VA Y

! + H KHOANG CACH GIUA CAC DIEM NUT ! OUTPUT: LAPU(2:N-1,2:M-1) LAPLAXIAN CUA U INTEGER N,M

REAL U(N,M),LAPU(N,M),H INTEGER IP1, IM1, JP1, JM1

N1=N-1 M1=M-1

DO I=2,N1 DO J=2,M1 IP1=I+1 IM1=I-1 JP1=J+1 JM1=J-1

LAPU(I,J)=(U(IP1,JP1)+U(IP1,JM1)+U(IM1,JP1) & +U(IM1,JM1)+4.*(U(IP1,J)+U(IM1,J)+U(I,JP1) & +U(I,JM1))-20.*U(I,J))/(6.*H**2)

ENDDO ENDDO RETURN

(198)

9.4.5 Giải phương trình truyền nhiệt

Bài toán truyền nhiệt toán phổ biến Phương trình truyền nhiệt dạng tổng qt có thểđược viết dạng:

⎟ ⎠ ⎞ ⎜ ⎝ ⎛ ∂ ∂ ∂ ∂ = ∂ ∂ x U A x t U (9.4.18) A hệ số dẫn nhiệt, t thời gian, x tọa độ điểm Nếu A số, phương

trình (9.4.18) có thểđược viết lại:

2 x U A t U ∂ ∂ = ∂ ∂ (9.4.19)

Để đơn giản trình bày, ta giả thiết A=1, phương trình truyền nhiệt có dạng đơn giản:

2 x U t U ∂ ∂ = ∂ ∂ (9.4.20) Giả sử xét truyền nhiệt đồng có độ dài hữu hạn L Bài toán yêu cầu xác

định phân bố U theo thời gian t vị trí x, tức xác định hàm U(x,t) Để giải toán phương pháp sai phân hữu hạn, ta chia thành đoạn Δx=h Ký hiệu bước thời gian tích phân Δt=k Khi đó điểm xi thời điểm tj ta có U(xi,tj) = U(ih,jk) = Uij, với i,j=0,1,2, Gọi uij xấp xỉ Uij (xi,tj), ta cần tìm tất uij điểm nút (xi,tj) Thuật tốn

để giải tốn có thểđược mơ tả sau

Xấp xỉ đạo hàm hai vế (9.4.20) sai phân hữu hạn, ta có:

k u u

t

U = i,j 1− i,j

∂ +

(9.4.21)

Tại thời điểm tj:

2 , , , 2 2 h u u u x

U = i j+ i ji j

∂ + − (9.4.22)

Tại thời điểm tj+1:

2 , , 1 , 2 2 h u u u x

U = i+ j+ + ij+ − i j+

∂ ∂

(9.4.23) Cộng vế (9.4.22) (9.4.23) ta được:

(ui j ui j ui j ui j ui j ui j)

h x U , , , 1 , , 1 , 2 2 2

1 + − + + −

= ∂ ∂ − + + + − +

+ (9.4.24)

Ký hiệu 2 h

k

r= , kết hợp (9.4.21) (9.4.24) ta được:

j i j i j i j i j i j

i r u ru ru r u ru

(199)

(9.4.25) Nếu khoảng thời gian tích phân T, số bước thời gian tính NT = T/k Vì độ dài

L nên số khoảng chia NX = L/h Do i=0,1,2, ,NX, j=0,1,2, ,NT Từ (9.4.25) ta có hệ phương trình:

⎪ ⎪ ⎪ ⎪ ⎩ ⎪⎪ ⎪ ⎪ ⎨ ⎧ + − + + = − + + − + − + = − + + − + − + = − + + − + − + = − + + − − − + + − + − + + + + + + + + + j Nx j Nx j Nx j Nx j Nx j Nx j j j j j j j j j j j j j j j j j j u u r ru ru u r ru u u r ru ru u r ru u u r ru ru u r ru u u r ru ru u r ru , , , , , 1 , , , , , , , , , , 1 , , , , , , , , 1 , ) 2 2 ( ) 2 2 ( ) 2 2 ( ) 2 2 ( ) 2 2 ( ) 2 2 ( ) 2 2 ( ) 2 2 ( (9.4.26)

Hệ gồm NX−1 phương trình, với NX−1 ẩn số giá trị ui,j+1 (i=1, ,NX−1) thời điểm tj+1, giá trị ui,j bước thời gian trước xem biết

Khi cho trước giá trị biên u0,j+1 uNX,j+1, ma trận hệ số vế trái hệ (9.4.26) ma trận ba đường chéo có dạng:

⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎠ ⎞ ⎜ ⎜ ⎜ ⎜ ⎜ ⎜ ⎝ ⎛ + − − + − − + − − + = ) 2 2 ( 0 0 0 0 0 ) 2 2 ( 0 0 ) 2 2 ( 0 ) 2 2 ( r r r r r r r r r r

A (9.4.27)

Đây ma trận dạng “ba đường chéo”, nghĩa ma trận có phần tử thuộc

đường chéo hai dãy khác khơng Dưới dạng ma trận, hệ (9.4.26) có thểđược viết:

(200)

Để giải hệ ta cần biết giá trị U(x, t) x t=0 (j=0, điều kiện ban đầu) t x nhận giá trị hai đầu mút (x=0 x=L, tức i=0 i=NX −điều kiện biên) Khi biết u j=0 u i=0 i=NX, vế phải hệ sẽđược xác định Giải hệ ta nhận ui,1 (tại bước thời gian j=1) Sau nhận ui,1, thay vào vế phải giải hệ ta nhận ui,2 Quá trình tiếp tục nhận ui,NT giá trị u bước thời gian cuối

Cuối ta có bước giải sau

1) Xác định giá trịđộ dài L, độ dài khoảng chia h, khoảng thời gian tích phân T bước thời gian k

2) Tính số khoảng chia theo x: NX = L/h, số bước tích phân thời gian NT = T/k 3) Tính giá trị r = k/h2

4) Xác định ba đường chéo ma trận A (9.4.27)

5) Xác định điều kiện ban đầu U(0:NX, 0) điều kiện biên U(0, 0:NT), U(NX, 0:NT) Nếu điều kiện cho dạng biểu thức giải tích ta phải tính giá trị chúng

điểm rời rạc, tức tính giá trị ui,0=U(xi,0), u0,j=U(0,tj), uNX,j=U(L,tj), i=0,1,2, ,NX, j=0,1,2, ,NT Trong thực tế, điều kiện ban đầu điều kiện biên cho tập giá trị rời rạc u: {u0,0, u1,0, , uNX,0}, {u0,0, u0,1, , u0,NT} {uNX,0, uNX,1, , uNX,NT}

6) Thực vòng lặp tích phân thời gian: a) Xuất phát từ j =

b) Tính vectơ vế phải G(1:NX−1) j c) Giải hệđể xác định U(1:NX, j+1) d) Nếu j<NT tăng j lên đơn vị

e) Quay lại bước b)

Quá trình lặp tiếp tục j=NT kết thúc

Để minh họa ta khảo sát ví dụ sau Giả sử L = (0 ≤ x ≤ 1), h = 0.1 k = 0.01, r = k/h2 = Số khoảng chia theo x NX = 1/0.1 = 10 (i = 0,1, ,10)

−Điều kiện biên chọn là: U(0, t) = U(1, t) = hay u0, j = uNX, j = (với j) −Điều kiện ban đầu là:

⎩ ⎨ ⎧

≤ ≤ −

≤ ≤ =

1 2

/ 1 ), 1 ( 2

2 / 1 0

, 2 ) 0 , (

x x

x x

x U

Hay ui,0 = { 0, 0.2, 0.4, 0.6, 0.8, 1.0, 0.8, 0.6, 0.4, 0.2, } Khi ta có chương trình tính sau

Ngày đăng: 22/05/2021, 17:37

Tài liệu cùng người dùng

Tài liệu liên quan