Các lỗi thường gặp khi tải matlap 2009 năm 2024

Cách này có tác dụng cập nhật các biến “đồng thời”; nghĩa là nó đọc cả hai biến cũ trước khi ghi ra hai giá trị mới.

Dưới đây là một cách làm khác có lợi là làm việc tính toán được đơn giản:

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

Xem xét đoạn mã này ta có thể thấy được nó tuân theo định luật bảo toàn số xe. Ngay cả khi giá trị của

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

1 là sai thì ít nhất tổng số xe vẫn còn đúng. Và từ đó dẫn đến Định luật thứ bẩy về gỡ lỗi:

Cách tốt nhất để tránh một lỗi là khiến nó không thể xảy ra.

Trong trường hợp này, việc bỏ những chi tiết thừa cũng loại trừ khả năng gây lỗi.

2. Các loại lỗi

Có bốn loại lỗi sau:

Lỗi cú pháp: Bạn đã viết một câu lệnh MATLAB mà không thể thực thi được vì nó vi phạm các quy tắc về cú pháp. Chẳng hạn, bạn không thể có hai toán hạng đi liền nhau mà không có toán tử, vì vậy

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

2 là một lỗi cú pháp. Khi MATLAB phát hiện ra lỗi cú pháp, nó sẽ hiển thị một thông báo lỗi và dừng chương trình. Lỗi thực thi: Chương trình của bạn đã bắt đầu chạy, nhưng rồi có điều gì trục trặc diễn ra. Chẳng hạn, nếu bạn cố gắng truy cập một biến chưa tồn tại thì đó là một lỗi thực thi. Khi MATLAB phát hiện được vấn đề, nó sẽ in ra thông báo lỗi và dừng lại. Lỗi logic: Chương trình chạy mà không phát sinh bất cứ thông báo lỗi nào, nhưng nó không thực hiện điều mong muốn. Vấn đề ta gặp ở mục trước, khi thay đổi giá trị của

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

4 trước lúc đọc giá trị cũ, là một lỗi logic. Lỗi số trị: Hầu hết những phép tính được thực hiện bởi MATLAB đều chỉ gần đúng. Trong đa số trường hợp, sai số là nhỏ và ta không quan tâm đến, nhưng đôi khi các sai số do làm tròn lại là một vấn đề.

Các lỗi cú pháp luôn dễ xử lý nhất. Đôi khi dòng thông báo lỗi có thể gây nhầm lẫn, nhưng thường MATLAB sẽ báo cho bạn biết lỗi ở đâu, ít ra là một vị trí gần đúng.

Các lỗi thực thi nói chung là khó hơn vì như tôi đã đề cập ở trên, MATLAB nói được vị trí của nó nhưng không nói nguyên nhân gây ra nó.

Các lỗi logic đều khó vì MATLAB chẳng giúp gì được. Chỉ có bạn mới biết được chương trình cần phải làm gì, vì vậy chỉ có bạn mới sửa được lỗi. Theo quan điểm của MATLAB, nếu chương trình không có gì sai thì lỗi nằm trong đầu bạn!

Các lỗi số trị có thể sẽ rất mẹo mực vì thật không rõ là cái sai có thuộc về bạn hay không. Với những tính toán đơn giản nhất, MATLAB cho ta các giá trị số có dấu phẩy động gần sát với giá trị đúng, có nghĩa là 15 chữ số ban đầu là đúng. Nhưng trong một số bài toán với đặc thù “tình trạng xấu”, có nghĩa là ngay cả khi chương trình của bạn đã đúng, các sai số do làm tròn vẫn tích tụ lại và số chữ số đúng sẽ ít đi. Đôi khi MATLAB có thể cảnh báo cho bạn biết điều này đang xảy ra, nhưng không phải luôn luôn như vậy! Độ chuẩn xác (số chữ số trong kết quả) không bao hàm độ chính xác (số chữ số đúng).

3. Sai số tuyệt đối và tương đối

Có hai cách nghĩ về các sai số về số trị, đó là tuyệt đối và tương đối.

Sai số tuyệt đối chính là độ chênh lệch giữa giá trị đúng và giá trị xấp xỉ. Ta thường biểu thị độ lớn của sai số này, mà bỏ qua dấu của nó, vì dù giá trị xấp xỉ có cao hay thấp thì cũng chẳng ảnh hưởng gì.

Chẳng hạn, ta muốn tính 9! bằng công thức √(18π) ⋅ (9/e)9. Đáp số đúng là 9 ⋅ 8 ⋅ 7 ⋅ 6 ⋅ 5 ⋅ 4 ⋅ 3 ⋅ 2 ⋅ 1 = 362880. Giá trị xấp xỉ tính được là 359536,87. Sai số tuyệt đối là 3343,13.

Thoạt nhìn, ta tưởng chừng như đây là sai số lớn—ta đã tính sai đến hơn 3000—nhưng cũng cần phải xét đến độ lớn của đại lượng mà ta cần tính. Chẳng hạn, $3000 là con số lớn khi nói về tiền lương năm của tôi, nhưng chẳng là gì cả nếu ta nói về khoản nợ của quốc gia.

Một cách tự nhiên để xử lý ván đề này là dùng sai số tương đối, vốn là tỉ lệ (hay số phần trăm) của sai số tuyệt đối so với giá trị đúng. Trong trường hợp này, ta cần chia sai số cho 362880, thu được 0,00921, tức là gần 1%. Với phần lớn các mục đích tính toán khác nhau, thì sai lệch 1% là đạt yêu cầu.

4. Vòng lặp for

Vòng lặp là một phần chương trình được thực hiện lặp đi lặp lại. Vòng lặp for là dạng vòng lặp có dùng câu lệnh

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

4.

Cách dùng vòng lặp

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

4 đơn giản nhất laf thực hiện lặp lại một hay nhiều câu lệnh với số lần định trước. Chẳng hạn, ở chương trước ta đã viết một đoạn mã có tên

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

6 để mô phỏng diễn biến chạy trong một tuần của những xe thuộc một công ty. Để mô phỏng diễn biến trong một năm, ta cần phải chạy nó 52 lần:

for i=1:52  
    car_update  
end  

Dòng thứ nhất giống như một lệnh gán, và nó đúng là một kiểu lệnh gán, nhưng được thực hiện nhiều lần. Lần đầu tiên được chạy, nó tạo ra biến

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

7 và gán cho nó giá trị bằng 1. Lần thứ hai,

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

7 nhận giá trị 2, và cứ như vậy cho đến 52.

Toán tử hai chấm,

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

9, biểu diễn một khoảng số nguyên. Theo tinh thần của cách kiểm tra từng phần, bạn có thể tạo ra một dãy từ dấu nhắc lệnh:

ans =  1     2     3     4     5  

Biến được dùng trong lệnh for này được gọi là biến vòng lặp. Theo thông lệ, ta thường lấy các tên

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

7,

for i=1:52  
    car_update  
end  

1 và

for i=1:52  
    car_update  
end  

2 để đặt cho các biến lặp.

Những câu lệnh bên trong vòng lặp được gọi là phần thân. Theo thông lệ, chúng được viết thụt đầu dòng để cho thấy rằng chúng nằm trong vòng lặp, tuy nhiên hình thức viết này không ảnh hưởng đến việc thực hiện chương trình. Điểm kết thúc của vòng lặp được chính thức đánh dấu bởi lệnh

for i=1:52  
    car_update  
end  

3.

Để xem vòng lặp hoạt động thế nào, bạn có thể chạy vòng lặp trong đó chỉ in ra biến lặp:

    i  
end
i = 1  
i = 2  
i = 3  
i = 4  
i = 5  

Như ví dụ trên cho thấy, bạn có thể chạy một vòng lặp từ dấu nhắc lệnh, nhưng ta thường đặt nó vào một tập tin lệnh hơn.

Hãy tạo ra một tập tin lệnh có tên

for i=1:52 > car_update > end >

4 trong đó dùng một vong lặp

atob = 0.05*a - 0.03*b > a = a - atob > b = b + atob >

4 để chạy

atob = 0.05*a - 0.03*b > a = a - atob > b = b + atob >

6 52 lần. Hãy nhớ rằng trước khi chạy

atob = 0.05*a - 0.03*b > a = a - atob > b = b + atob >

6, bạn phải gán các giá trị cho

anew = a - 0.05*a + 0.03*b > bnew = b + 0.05*a - 0.03*b > a = anew > b = bnew >

4 và

anew = a - 0.05*a + 0.03*b > bnew = b + 0.05*a - 0.03*b > a = anew > b = bnew >

5. Với bài tập này, hãy bắt đầu bằng các giá trị

1:5 > ans = 1 2 3 4 5 >

0 và

1:5 > ans = 1 2 3 4 5 >

1.

Nếu mọi việc trôi chảy, chương trình của bạn sẽ hiển thị một đoạn dài các con số trên màn hình. Nhưng thường có quá nhiều số để màn hình hiện ra hết; và ngay cả có hiện hết đi nữa cũng rất khó diễn giải được. Có một đồ thị sẽ tốt hơn!

5. Đồ thị

ans =  1     2     3     4     5  

2 là một hàm vẽ đồ thị rất đa năng, giúp ta vẽ các điểm, các đường trên hệ tọa độ hai chiều. Thật không may, vì quá đa năng nên nó có thể trở nên khó dùng. (và khó tra cứu thông tin về hàm này!) Ta sẽ bắt đầu một cách đơn giản và dần làm khó hơn.

Để chấm một điểm, ta gõ vào undefined

Một Figure Window (cửa sổ hình vẽ) sẽ xuất hiện với một đồ thị trên đó có chấm một điểm màu xanh lam tại tọa độ x bằng 1 và y bằng 2. Để khiến cho điểm này dễ nhìn hơn, bạn có thể chọn một hình khác: undefined

Chữ cái ở trong cặp dấu nháy đơn là một chuỗi chỉ định hình thức của điểm cần chấm. Bạn cũng có thể chỉ định màu sắc: undefined

ans =  1     2     3     4     5  

3 viết tắt cho red (đỏ); các màu khác gồm có green (lục), blue (lam), cyan (da trời), magenta (tím hồng), yellow (vàng) và black (đen). Các hình khác gồm có

ans =  1     2     3     4     5  

4,

ans =  1     2     3     4     5  

5,

ans =  1     2     3     4     5  

6,

ans =  1     2     3     4     5  

7 (square / hình vuông),

ans =  1     2     3     4     5  

8 (diamond / hình thoi), và

ans =  1     2     3     4     5  

9 (hình tam giác).

Khi bạn dùng hàm

ans =  1     2     3     4     5  

2 theo cách này, mỗi lúc nó chỉ vẽ được một điểm. Nếu bạn chạy

ans =  1     2     3     4     5  

2 lần nữa, nó xóa toàn bộ hình vẽ trước khi vẽ hình mới. Lệnh

    i  
end
i = 1  
i = 2  
i = 3  
i = 4  
i = 5  

2 giúp bạn thay đổi đặc tính nêu trên.

    i  
end
i = 1  
i = 2  
i = 3  
i = 4  
i = 5  

3 báo với MATLAB rằng không được xóa hình cũ khi vẽ hình mới; và

    i  
end
i = 1  
i = 2  
i = 3  
i = 4  
i = 5  

4 trở lại đặc tính ban đầu.

Hãy thử các lệnh này:

plot(2, 2, 'o')  

Bạn sẽ nhìn thấy một hình có hai điểm. MATLAB co giãn tỉ lệ đồ thị một cách tự động sao cho các trục chạy từ giá trị nhỏ nhất trên đồ thị đến giá trị lớn nhất. Vì vậy ở ví dụ này, các điểm chấm xuất hiện ở hai góc.

Hãy sửa lại

for i=1:52 > car_update > end >

4 sao cho qua mỗi vòng lặp, chương trình sẽ chấm lên đồ thị giá trị của

anew = a - 0.05*a + 0.03*b > bnew = b + 0.05*a - 0.03*b > a = anew > b = bnew >

4 theo

atob = 0.05*a - 0.03*b > a = a - atob > b = b + atob >

7.

Một khi chương trình của bạn chạy được, hãy sửa lại để nó chấm các giá trị của

anew = a - 0.05*a + 0.03*b > bnew = b + 0.05*a - 0.03*b > a = anew > b = bnew >

4 bằng vòng tròn đỏ và của

anew = a - 0.05*a + 0.03*b > bnew = b + 0.05*a - 0.03*b > a = anew > b = bnew >

5 bằng hình thoi xanh lam.

Thêm nữa: nếu bạn dùng

for i=1:5 > i > end i = 1 > i = 2 > i = 3 > i = 4 > i = 5 >

3 để ngăn không cho MATLAB xóa hình vẽ, bạn vẫn có thể tự xóa hình theo ý muốn bằng lệnh

plot(1, 2) >
1.

6. Dãy

Trong toán học, một dãy là một tập hợp các số tương ứng với các số nguyên dương. Các số trong dãy được gọi là phần tử. Theo kí hiệu toán học, các phần tử được kèm theo các chỉ số dưới, vì vậy phần tử đầu tiên của dãy A là A1, tiếp theo là A2, và cứ như vậy.

Vòng lặp

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

4 là một cách tự nhiên để tính các phần tử trong một dãy. Chẳng hạn, trong dãy hình học, mỗi phần tử là một bội số (với hệ số không đổi) của số liền trước. Cụ thể, hãy xét dãy số với A1 = 1 và tỉ lệ Ai+1/Ai = 2, với mọi i. Nói cách khác, mỗi phần tử chỉ lớn bằng nửa phần tử liền trước nó.

Vòng lặp sau đây tính ra 10 phần tử đầu của A:

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

0

Mỗi lượt lặp, ta tìm được phần giá trị tiếp theo của

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

4 bằng cách chia giá trị trước cho 2. Lưu ý rằng dãy chỉ số bắt đầu từ 2 vì giá trị đầu của

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

4 tương ứng với A1, vì vậy lượt lặp đầu tiên ta đi tính A2.

Mỗi lần qua vòng lặp, ta thay thế phần tử trước bởi phần tử kế tiếp, vì vậy về cuối,

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

4 chứa phần tử thứ 10. Các phần tử khác được hiển thị trên màn hình, nhưng chúng không được lưu lại trong một biến nào. Sau này, ta sẽ xem cách lưu toàn bộ các phần tử của dãy vào một véc-tơ.

Vòng lặp này tính dãy theo cách truy hồi, nghĩa là mỗi phần tử đều phụ thuộc vào phần tử liền trước nó. Với dạng dãy này ta cũng có thể tính trực tiếp phần tử thứ i, theo một hàm của i, mà không cần dùng đến phần tử đứng trước. Theo cách viết toán học, Ai = A1ri–1.

Hãy viết một tập tin lệnh có tên
plot(1, 2) >
6 trong đó dùng vòng lặp để tính các phần tử của A một cách trực tiếp.

7. Chuỗi

Trong toán học, chuỗi là tổng các phần tử của một dãy. Cách đặt tên này không hay trong tiếng Anh (“sequence” và “series” gần như có chung nghĩa); nhưng trong toán thì dãy là một tập hợp số, còn chuỗi lại là một biểu thức (một tổng) với một giá trị duy nhất. Theo kí hiệu toán học, một chuỗi thường được viết với dấu tổng ∑.

Chẳng hạn, tổng của 10 phần tử đầu tiên của A là

∑i=110Ai

Một vòng lặp

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

4 là cách tự nhiên để tính giá trị của chuỗi này:

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

1 undefined

8 là phần tử đầu tiên của dãy, vì vậy ở mỗi lượt lặp,

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

4 là phần tử thứ i.

Biến undefined

0, theo cách dùng ở đây, đôi khi được gọi là biến tích lũy; tức là một biến mà dồn lại lần lượt từng kết quả của các phép tính. Trước vòng lặp ta đặt biến này bằng 0. Mỗi lượt lặp ta cộng nó với phần tử thứ i. Ở cuối vòng lặp, undefined

0 sẽ chứa tổng của các phần tử. Vì đó là giá trị mà ta cần tìm, ta gán nó cho undefined

2.

Ví dụ trên đã tính các phần tử của chuỗi một cách trực tiếp; bạn hãy thử viết một tập tin lệnh tên là
plot(1, 2, 'o') >
3 để tính cùng tổng đó nhưng với từng phần tử được tính theo cách truy hồi. Bạn sẽ phải cẩn thận về các vị trí bắt đầu và kết thúc vòng lặp.

8. Khái quát hóa

Như đã nói, ví dụ trên luôn luôn lấy tổng 10 phần tử đầu tiên của dãy, nhưng ta có thể tò mò muốn biết giá trị undefined

0 sẽ như thế nào khi ta tăng số lượng các số hạng có trong chuỗi. Nếu bạn đã biết về chuỗi hình học, bạn thấy rằng chuỗi này hội tụ về 2; nghĩa là khi số các số hạng tiến đến vô cùng, thì tổng sẽ tiệm cận về 2.

Để thấy được liệu điều đó có đúng không, trong chương trình ta sẽ thay thế hằng số, 10, với một biến có tên undefined

5:

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

2

Bây giờ đoạn chương trình có thể tính với bao nhiêu số hạng cũng được, với điều kiện đầu là bạn phải đặt undefined

5 trước khi chạy chương trình này. Sau đây là cách chạy chương trình với các giá trị undefined

5 khác nhau:

anew = a - 0.05*a + 0.03*b  
bnew = b + 0.05*a - 0.03*b  
a = anew  
b = bnew  

3

Rõ ràng là nó đang hội tụ về 2.

Việc thay thế một hằng số bởi một biến được gọi là khái quát hóa. Thay vì tính với một số lượng cụ thể và cố định các số hạng, chương trình mới này tổng quát hơn; nó có thể tính với số các số hạng bất kì.

Đây là một ý tưởng quan trọng mà ta sẽ quay về khi thảo luận đến các hàm.

9. Thuật ngữ

sai số tuyệt đối: Độ chênh lệch giữa giá trị xấp xỉ và kết quả đúng. sai số tương đối: Độ chênh lệch giữa giá trị xấp xỉ và kết quả đúng, biểu diễn dưới dạng một phần hoặc số phần trăm của giá trị đúng. vòng lặp: Phần của chương trình được chạy đi chạy lại nhiều lần. biến lặp: Biến được định nghĩa trong một câu lệnh

atob = 0.05*a - 0.03*b  
a = a - atob  
b = b + atob  

4; nó được gán các giá trị khác nhau qua mỗi lượt lặp. khoảng: Tập hợp các giá trị được gán cho một biến lặp, thường được biểu thị bởi toán tử hai chấm, chẳng hạn undefined

9. phần thân: Những câu lệnh bên trong vòng lặp được thực hiện lặp lại nhiều lần. dãy: Trong toán học, một tật hợp các số tương ứng với những số nguyên. phần tử: Một thành viên của tập hợp các số trong dãy. truy hồi: Cách tính phần tử kế tiếp trong dãy dựa trên những phần tử liền trước. trực tiếp: Cách tính phần tử trong dãy mà không cần dùng đến những phần tử trước. chuỗi: Tổng của các phần tử trong một dãy. biến tích lũy: Biến được dùng để tích tụ kết quả từng ít một. khái quát hóa: Cách làm chương trình linh hoạt hơn, chẳng hạn bàng việc thay thế một giá trị cụ thể bằng một biến có thể nhận giá trị bất kì.

10. Bài tập

Ta đã thấy các dãy Fibonacci, F, vốn được định nghĩa theo cách truy hồi như sau

Fi = Fi–1 + Fi–2

Để bắt đầu, bạn phải chỉ định hai phần tử đầu tiên, nhưng một khi có hai phần tử này rồi, bạn có thể tính toàn bộ các phần tử còn lại. Dãy Fibonacci thông dụng nhất khởi đầu với F1 = 1 và F2 = 1.

Hãy viết một đoạn mã lệnh có tên là undefined

0 trong đó dùng một vòng lặp để tính 10 phần tử đầu tiên của dãy Fibonacci. Điều kiện cuối của chương trình là gán phần tử thứ 10 cho undefined

2.