Trong chương 4 đã xét sự điều khiển được thực hiện thông qua những lệnh cho phép chương trình chọn những nhánh khác nhau để thực hiện. Đồng thời, ta cũng đã một số lần sử dụng kết hợp lệnh IF lôgic và lệnh chuyển điều khiển vô điều kiện GOTO để tổ chức những vòng lặp dạng:
| IF (Biểu thức lôgic) THEN | |
| Lệnh 1 | |
| Lệnh 2 | |
| . . . | |
| Lệnh | |
| GOTO | |
| END IF |
Cấu trúc này gọi là vòng lặp có điều kiện (While Loop): Khi và chừng nào biểu thức lôgic trong lệnh IF có giá trị .TRUE. thì nhóm lệnh từ lệnh 1 đến lệnh lần lượt thực hiện, nhưng lệnh GOTO ở cuối luôn luôn chuyển điều khiển lên nhãn và hình thành vòng lặp. Vòng lặp này có những đặc điểm sau:
1) Trường hợp biểu thức lôgic có giá trị .FALSE. ngay từ đầu, thì quá trình lặp sẽ không xảy ra;
2) Trong nhóm lệnh từ lệnh 1 đến lệnh bên trong vòng lặp nhất thiết phải có một lệnh nào đó làm thay đổi giá trị của biểu thức lôgic thành .FALSE., vậy số lần lặp phụ thuộc vào giá trị khởi đầu của biểu thức lôgic và sự biến đổi giá trị của nó bên trong chính vòng lặp.
Trong bài này ta xét một cấu trúc lặp khác mà điều kiện và số lần lặp được xác định ngay từ khi bắt đầu quá trình lặp với việc sử dụng vòng lặp DO (DO Loop). Trong chương tiếp sau sẽ xét một tính năng quan trọng của vòng lặp DO, gọi là vòng lặp ẩn, để tổ chức nhập, xuất các biến có chỉ số rất hay gặp trong thực tiễn.
Vòng lặp DO
Cú pháp của lệnh DO và vòng lặp DO
Dạng tổng quát của lệnh DO như sau:
DO
trong đó hằng là nhãn của lệnh kết thúc của vòng lặp, là một biến số được dùng như là chỉ số đếm vòng lặp, giá trị đầu gán cho chỉ số đếm, giá trị cuối dùng để xác định khi nào vòng lặp DO kết thúc và gia số, giá trị được cộng vào chỉ số đếm mỗi lần vòng lặp thực hiện.
Những giá trị đầu, giá trị cuối và gia số gọi là các tham số của vòng lặp. Nếu trong lệnh DO không ghi gia số thì ngầm định là 1. Khi giá trị của chỉ số đếm lớn hơn giá trị cuối thì điều khiển được chuyển cho lệnh đứng sau lệnh kết thúc vòng lặp. Lệnh kết thúc vòng lặp thường dùng là lệnh CONTINUE, có dạng tổng quát là
n CONTINUE
trong đó nhãn phù hợp với nhãn mà lệnh DO ở trên đã chỉ định.
Vậy dạng tổng quát của vòng lặp DO có thể viết như sau:
| DO | |
| Lệnh 1 | |
| . . . | |
| Lệnh | |
| CONTINUE |
Ta lấy thí dụ giải bài toán tính tổng của 50 số nguyên dương đầu tiên
để minh họa vòng lặp DO và so sánh nó với vòng lặp While mà ta đã xét ở bài trước:
| Vòng lặp DO | Vòng lặp While | ||
| SUM = 0.0 | SUM = 0.0 | ||
| DO 10 NUM = 1, 50 | NUM = 1 | ||
| SUM = SUM + NUM | 10 | IF (NUM .LE. 50) THEN | |
| 10 | CONTINUE | SUM = SUM + NUM | |
| NUM = NUM + 1 | |||
| GO TO 10 | |||
| END IF |
Trong vòng lặp DO trên đây chỉ số đếm NUM được khởi xướng bằng 1. Vòng tiếp tục lặp cho đến khi giá trị của NUM lớn hơn 50. Vì tham số thứ ba bỏ qua nên NUM tự động tăng lên 1 ở cuối mỗi lần lặp. Ta thấy rằng vòng lặp DO viết ngắn gọn hơn vòng lặp While, nhưng cả hai tính cùng một giá trị của biến SUM. Tuy nhiên, trong vòng lặp While ở mỗi lần lặp biểu thức lôgic luôn phải được ước lượng lại vì mỗi lần biến NUM được thay bởi giá trị mới.. Trong khi đó ở vòng lặp DO số lần lặp đã được tính trước trong lệnh DO. Đó là sự khác nhau cơ bản của hai loại vòng lặp.
Người ta cũng có thể dùng cú pháp sau đây cho vòng lặp DO:
| DO | |
| Lệnh 1 | |
| . . . | |
| Lệnh | |
| END DO |
Những quy tắc cấu trúc và thực hiện vòng lặp DO
1) Chỉ số đếm phải là một biến số, biến đó có thể là kiểu nguyên hoặc thực, nhưng không thể là biến có chỉ số.
2) Các tham số của vòng DO có thể là hằng, biến hay biểu thức nguyên hoặc thực. Gia số có thể là số dương, số âm, nhưng không thể bằng không.
3) Vòng DO có thể dùng bất kỳ lệnh thực hiện nào không phải là một lệnh chuyển điều khiển, lệnh IF hay một lệnh DO khác làm lệnh cuối vòng. Lệnh CONTINUE là một lệnh thực hiện chuyên dùng làm lệnh cuối vòng; mặc dù có thể dùng những lệnh khác, nhưng nói chung nên dùng lệnh CONTINUE để chỉ cuối vòng lặp một cách tường minh.
4) Sự kiểm tra kết thúc lặp thực hiện ở đầu vòng lặp. Nếu giá trị đầu của chỉ số đếm lớn hơn giá trị cuối và gia số là số dương thì sự lặp không diễn ra, các lệnh bên trong vòng lặp bị bỏ qua và điều khiển chuyển tới lệnh đứng sau lệnh cuối cùng của vòng lặp.
5) Không được thay đổi giá trị của chỉ số đếm bằng một lệnh nào khác bên trong vòng DO trong khi thực hiện vòng lặp.
6) Sau khi vòng lặp đã bắt đầu thực hiện thì những thay đổi các giá trị của các tham số không có ảnh hưởng gì tới sự lặp.
7) Nếu gia số là âm, sự lặp sẽ kết thúc khi giá trị chỉ số đếm nhỏ hơn giá trị cuối.
8) Ta có thể thóat ra khỏi vòng DO trước khi nó kết thúc lặp. Khi đó giá trị của chỉ số đếm sẽ bằng giá trị ngay trước khi thóat. (Nhưng nói chung không nên làm điều này. Nếu ta muốn thóat ra khỏi vòng lặp trước khi nó kết thúc một cách tự nhiên, thì ta cấu trúc lại vòng lặp theo kiểu vòng lặp While để giữ tính cấu trúc của chương trình).
9) Thực hiện xong vòng lặp, chỉ số đếm chứa một giá trị vượt quá giá trị cuối.
10) Bao giờ cũng đi vào vòng lặp thông qua lệnh DO để vòng lặp được khởi xướng một cách đúng đắn. Không bao giờ được dùng lệnh GO TO chuyển từ bên ngoài vào bên trong vòng DO.
11) Số lần lặp có thể tính bằng công thức
trong đó dấu ngoặc vuông chỉ sự cắt bỏ thập phân của thương số. Nếu giá trị này âm thì sự lặp không xảy ra.
Thí dụ ứng dụng vòng lặp DO
Thí dụ 9: Lập vòng lặp bằng lệnh DO. Lập bảng giá trị của đa thức trên đoạn từ 1 đến 10 với bước .
| PRINT * , ' POLYNOMIAL MODEL' | |
| PRINT * PRINT * , 'TIME POLYNOMIAL' | |
| DO 15 I = 1, 10 | |
| POLY = 3. * REAL (I) ** 2 + 4.5 | |
| PRINT 10 , I , POLY | |
| 10 | FORMAT (1X, I2, 8X, F6.2) |
| 15 | CONTINUE |
| END |
Thí dụ 10: Tìm phần tử cực đại của chuỗi số. Ta giải bài toán này theo thuật giải biểu diễn bởi giả trình sau:
| 1) với từ 1 đến 10 | |
| nhập | |
| 2) | |
| 3) với từ 2 đến 10 | |
| nếu thì | |
| 4) in |
Từ giả trình này dễ dàng chuyển thành chương trình Fortran dưới đây:
| REAL B(10) | |
| DO 2 I = 1, 10 | |
| READ *, B (I) | |
| 2 | CONTINUE |
| BMAX = B (1) | |
| DO 3 I = 2, 10 | |
| IF (BMAX .LT. B (I)) BMAX = B (I) | |
| 3 | CONTINUE |
| PRINT *, ' B MAX = ' , BMAX | |
| END |
Thí dụ 11: Tổ chức vòng lặp với bước số thập phân. In bảng giá trị hàm tại Ta đưa ra một biến nguyên I sao cho biến này sẽ nhận các giá trị 1, 2, ..., 11 tương ứng với Khi đó .
| DO 17 I = 1, 11 | |
| X = 0.1 * (I - 1) | |
| Y = SIN (X) | |
| PRINT 10 , X, Y | |
| 10 | FORMAT (20X, F4.2, 10X, E10.3) |
| 17 | CONTINUE |
| END |
Hãy lưu ý rằng ở đây ta đã tránh sử dụng vòng lặp DO với các tham số thực như:
DO 15 X = 0.0 , 1.0 , 0.1
để phòng ngừa hiện tượng cắt trong máy tính. Giả sử rằng giá trị 0.1 được lưu như một giá trị hơi nhỏ hơn 0.1 trong hệ máy tính đang dùng, mỗi lần thêm 0.1 cho chỉ số đếm, máy có thể thêm ít hơn theo dự định. Ngoài ra, trong trường hợp này ta có thể thực hiện lặp quá mất một lần theo dự định vì giá trị giới hạn cuối cũng có thể không chính xác bằng 1.0.
Vòng DO lồng nhau
Vòng DO có thể được lồng trong một vòng DO khác, cũng giống như cấu trúc IF lồng trong cấu trúc IF khác. Khi tổ chức các vòng DO lồng hãy tuân thủ những quy tắc sau đây:
1) Vòng DO lồng bên trong không thể dùng chính chỉ số đếm cùng với vòng DO ngoài chứa nó.
2) Vòng DO lồng phải kết thúc bên trong vòng DO ngoài.
3) Các vòng DO độc lập nhau có thể dùng cùng chỉ số đếm, thậm chí khi chúng cùng nằm trong một vòng DO ngoài.
4) Khi một vòng DO lồng bên trong một vòng DO khác, thì vòng DO trong thực hiện trọn vẹn từng lần lặp ở vòng DO ngoài.
5) Mặc dù các vòng DO lồng có thể dùng cùng một dòng lệnh cuối CONTINUE, nhưng ta nên kết thúc mỗi vòng bằng một lệnh CONTINUE riêng biệt để làm sáng rõ chương trình.
Dưới đây dẫn một số thí dụ về các vòng DO đúng và các vòng DO sai:
a) Những vòng DO đúng:
| DO 15 I = 1, 5 | DO 15 I = 1, 5 | ||
| DO 10 J = 1, 8 | DO 10 K = 1, 8 | ||
| DO 5 K = 2, 10, 2 | . . . | ||
| . . . | 10 | CONTINUE | |
| 5 | CONTINUE | DO 5 K = 2, 10, 2 | |
| 10 | CONTINUE | . . . | |
| 15 | CONTINUE | 5 | CONTINUE |
| 15 | CONTINUE |
b) Những vòng DO sai:
| DO 15 I = 1, 5 | DO 20 J = 1, 5 | ||
| DO 10 J = 1, 8 | DO 10 J = 1, 8 | ||
| DO 5 K = 2, 10, 2 | . . . | ||
| . . . | 10 | CONTINUE | |
| 10 | CONTINUE | DO 15 K = 2, 10, 2 | |
| . . . | DO 15 K = 2, 10, 2 | ||
| 5 | CONTINUE | . . . | |
| 15 | CONTINUE | 15 | CONTINUE |
| 20 | CONTINUE |
Thí dụ 12: Tổ chức vòng DO lồng nhau. Viết chương trình nhập 15 phần tử của mảng số thực X, sắp xếp lại các phần tử mảng theo thứ tự giảm dần và in lên màn hình các mảng cũ và mới thành hai cột.
| REAL X(15), Y(15) | |
| N = 15 | |
| DO 3 I =1, N | |
| READ * , X (I) | |
| Y (I) = X (I) | |
| 3 | CONTINUE |
| DO 2 I = 1, N - 1 | |
| K = I | |
| DO 4 J = I + 1, N | |
| IF (Y (K) .LT. Y (J)) K = J | |
| 4 | CONTINUE |
| IF (K .NE. I) THEN | |
| TG = Y (I) | |
| Y (I) = Y (K) | |
| Y (K) = TG | |
| END IF | |
| 2 | CONTINUE |
| DO 7 I = 1, N | |
| PRINT 5 , X (I), Y (I) | |
| 7 | CONTINUE |
| 5 | FORMAT (1X, 2F10.2) |
| END |
Trong thí dụ này, ta thấy có mặt ba vòng DO độc lập nhau:
DO 3 I =1, N (dòng thứ 3)
DO 2 I =1, N-1 (dòng thứ 7)
DO 7 I = 1, N (dòng thứ 18)
do đó, chúng có thể dùng cùng một chỉ số đếm là biến I. Bên trong vòng DO thứ hai, ta thấy xuất hiện một vòng DO thứ tư:
DO 4 J = I + 1, N (dòng thứ 9),
vòng DO này là vòng DO lồng, nó phải có chỉ số đếm riêng và ta dùng lệnh kết thúc nó là lệnh
4 CONTINUE
để nhấn mạnh sự phân biệt với vòng DO ngoài có lệng kết thúc là
2 CONTINUE
Thí dụ 13: Tính giai thừa. Khi số nguyên không âm, biểu thức gọi là giai thừa của . Các giá trị của giai thừa được tính theo quy luật:
Giá trị của giai thừa của số nguyên cũng còn được ước lượng bằng công thức Stirling có dạng:
trong đó . Viết chương trình in các giá trị giai thừa của các số nguyên từ 0 đến 10 theo cách tính chính xác và theo công thức ước lượng của Stirling.
| PRINT 4 | |
| 4 | FORMAT (1X, 'GIAI THUA CUA CAC SO TU 0 DEN 10' |
| * | //1X, T3, 'N', T12, 'N!', T16, 'STIRLING''S FORMULA' /) |
| FAC = 1. | |
| DO 7 I = 0, 10 | |
| IF (I .GT. 1) FAC = FAC * I | |
| PRINT 5, I, FAC, SQRT (2.*3.141593*I)*(I / 2.718282)** I | |
| 5 | FORMAT (1X, I2, F10.0, F20.0) |
| 7 | CONTINUE |
| END |
Trong chương trình này, vì giai thừa được tính liên tục với các số từ 0 đến 10, nên giai thừa của một số sau được tính bằng tích của số đó nhân với giai thừa của số trước nó. Hãy chú ý cách dùng dấu gạch chéo để tạo xuống dòng khi in tiêu đề: hai dấu gạch chéo đầu chỉ định cho lệnh PRINT in xong dòng chữ GIAI THUA CUA CAC SO TU 0 DEN 10 thì xuống dòng hai lần, sau khi in dòng tiêu đề cột, dấu gạch chéo thứ ba gây xuống dòng một lần để chuẩn bị in dữ liệu theo dòng lệnh in trong vòng lặp DO. Các đặc tả T3, T12, T16 trong dòng lệnh 4 FORMAT chỉ định xuất chữ N ở vị trí 3, N! ở vị trí 12 và 13, chữ STIRLING'S FORMULA bắt đầu ở vị trí thứ 16 của dòng tiêu đề cột. Kết quả xuất ra của chương trình này sẽ có dạng dưới đây:
GIA TRI GIAI THUA CAC SO TU 0 DEN 10
N N! STIRLING'S FORMULA
0 1. 0.
1 1. 1.
2 2. 2.
3 6. 6.
4 24. 24.
5 120. 118.
6 720. 710.
7 5040. 4980.
8 40320. 39902.
9 362880. 359537.
10 3628800. 3598694.
Bài tập
1. Tính số lần lặp trong các trường hợp dùng lệnh DO sau đây. Giả thiết rằng các chỉ số đếm là những biến nguyên:
1) DO 5 I = 1, 8 2) DO 10 COUNT = -4, 4
3) DO 10 K = 15, 3, -1 4) DO 10 TIME = -5, 15, 3
5) DO 10 TIME = 50, 250, 25 6) DO 10 IND = 72, 432, 4
2. Xác định giá trị của biến nguyên IDEM sau khi những vòng DO dưới đây thực hiện xong. Giả sử biến này được gán giá trị không trước mỗi vòng lặp.
| 1) | DO 5 I = 1, 8 | 2) | DO 5 IDEX =0, 7 |
| IDEM = IDEM + 1 | IDEM = IDEM - 2 | ||
| 5 | CONTINUE | 5 | CONTINUE |
| 3) | DO 5 NUM = 8, 0, -1 | 4) | DO 5 M = 5, 5 |
| IDEM = IDEM + 2 | IDEM = IDEM + (-1) **M | ||
| 5 | CONTINUE | 5 | CONTINUE |
3. Một hòn đá được ném với tốc độ ban đầu và nghiêng một góc so với mặt đất. Nếu bỏ qua lực cản ma sát với không khí thì khoảng cách theo chiều ngang kể từ vị trí ban đầu và độ cao (tính bằng mét) của nó tại thời gian (giây) biểu thị bằng các phương trình sau:
trong đó gia tốc trọng lực ( ). Viết chương trình đọc vận tốc ban đầu và góc và sau đó in bảng các khoảng cách và độ cao của hòn đá với thời gian cách nhau 0,25 giây cho tới khi độ cao trở thành giá trị âm, tức lúc hòn đá rơi xuống mặt đất.
4. Hãy tổ chức lại các vòng lặp trong thí dụ 13 bằng cách sử dụng kết hợp lệnh IF lôgic và lệnh chuyển điều khiển vô điều kiện GOTO. Phân tích sự khác nhau của hai cách tổ chức vòng lặp.
5. Giả sử các giá trị quan trắc hai đại lượng và được cho như trong bảng 4.4 (trang 79). Hãy viết chương trình tính các đặc trưng thống kê: trung bình , phương sai , độ lệch bình phương trung bình , hệ số tương quan giữa hai đại lượng và lập phương trình hồi quy dạng:
,
trong đó:
, ,
, ,
, ,
.
6. Viết chương trình tính trị gần đúng của tích phân
theo công thức hình thang với sai số không lớn hơn 0,0001, xác định số hình thang cần chia để đạt sai số đó. Chương trình cho phép nhập từ bàn phím các cận tích phân và in kết quả lên màn hình thành các dòng như sau (thí dụ nếu và ):
A = 0.5
B = 1.5
SO HINH THANG = 16
TICH PHAN BANG = 0.9604
7. Viết chương trình cho phép nhập từ bàn phím một góc tính bằng độ, đổi góc đó thành rađian và tính giá trị gần đúng của với độ chính xác tới 0,0001 theo công thức khai triển sau đây:
In kết quả lên màn hình thành một dòng như sau (thí dụ):
A = 60.000 (DO) cos A = 0.5000 cos A theo hàm chuẩn = 0.5000
8. Viết chương trình cho phép nhập từ bàn phím hai số nguyên (nhỏ hơn 10) tuần tự chỉ số dòng và số cột của một ma trận. Sau đó tính các phần tử của ma trận sao cho mỗi phần tử là một số nguyên gồm hai chữ số, chữ số đầu chỉ số thứ tự dòng và chữ số sau chỉ số thứ tự cột. In ma trận đó lên giữa màn hình dưới dạng bảng số thẳng dòng, thẳng cột, thí dụ:
| 11 | 12 | 13 | 14 |
| 21 | 22 | 23 | 24 |
| 31 | 32 | 33 | 34 |
| 41 | 42 | 43 | 44 |
| 51 | 52 | 53 | 54 |
| 61 | 62 | 63 | 64 |