3.8 MATLAB程序的調試和優化
在MATLAB的程序調試過程中,不僅要求程序能夠滿足設計者的設計需求,而且還要求程序調試能夠優化程序的性能,這樣使得程序調試有時比程序設計更為復雜。MATLAB提供了強大的程序調試功能,合理的運用MATLAB提供的程序調試工具尤其重要。本節從MATLAB程序調試的方法和過程開始介紹,先讓用戶懂得合理運用MATLAB的程序調試功能,再總結MATLAB程序優化的方法,從而達到實現提高程序性能的目的。
3.8.1 MATLAB程序調試方法和過程(1)
MATLAB是一種解釋和執行同時進行的語言,這使得程序的調試變得相對便利,尤其是MATLAB具有良好的所見即所得特性。在MATLAB程序調試過程中,可運用的除了一系列調試函數外,MATLAB還提供了專門的調試器,即M文件編譯器,通過該M文件編譯器和調試函數的共同使用,用戶能夠完成大部分的程序調試工作。
1.調試的基本任務
程序調試(Debug)的基本任務就是要找到並去除程序中的錯誤。程序的錯誤大致可以分為如下三類。
語法錯誤:由於程序員疏忽、輸入不正確等原因而造成的代碼違背程序語言規則的錯誤。
運行錯誤:由於對所求解問題的理解差異,導致程序流程出錯或對程序本身的特性認識有誤而造成的程序執行結果錯誤的情況。
異常:程序執行過程中由於不滿足條件而造成的程序執行錯誤。
語法錯誤是初學者最常犯的錯誤,例如,變量或函數名拼寫錯誤、缺少引號或括號等。這類錯誤對於熟練掌握MATLAB的用戶來說很容易避免,並且當MATLAB運行發現這些錯誤時會立即標識出這些錯誤,並向用戶說明錯誤的類型以及在M文件中的位置,下面用一個例子來說明,在debug.m文件中輸入如下內容:
1 1 A=[1 2 3,4 5 6,7 8 9]; %定義矩陣A 2 2 B=[1 2 3 4,5 6 7 8,9 10 11 12,13 14 15 16]; %定義矩陣B 3 3 C=A*B %C為矩陣A和B相乘
運行時則會出現如下錯誤:
- ??? Error using ==> mtimes
- Inner matrix dimensions must agree.
在上述矩陣四則運算的例子中,矩陣A和矩陣B的維數不滿足運算前置條件,即兩個矩陣的維數不同不能進行運算。
運行錯誤也能夠被MATLAB發現,但是用戶卻不知道錯誤到底發生在何處,也就不能通過查詢函數工作區域的方法來查詢錯誤來源,更多時候是MATLAB無法發現運行錯誤,但是運行結果在驗證時出錯。這類錯誤的處理方法多是依靠編程經驗解決,下面就求解方程組的例子來進行說明,在命令窗口中輸入以下指令:
- >> A=[1 2 3;4 5 6;7 8 9];
- >>B=[9 8 7;6 5 4;3 2 1];
- >>x = B/A %x為矩陣B除以A
運行結果為:
- x =
- -2.6667 0 1.6667
- -2.1667 0 1.1667
- -1.6667 0 0.6667
該結果在不同計算機的不同版本的MATLAB下可能不完全相同。為了驗證這個結果,在命令窗口中輸入如下命令:
- >> A*x-B; %矩陣A,x和B進行計算
- >> norm(A*x-B) %返回表達式計算結果的最大奇異值
運算結果為:
- ans =
- 74.4236
顯然x不是A*x=B的解。
說明這就是一個簡單的運行錯誤,MATLAB同樣有運行結果,但是進行驗證時結果卻不正確。原因是在求解A*x=B方程的解時,應該不能用B右除A,而應該是左除,例如,在MATLAB命令窗口輸入如下命令:
- >> x=A\B
運行結果為:
- x =
- -27 -26 -17
- 42 41 24
- -16 -16 -8
驗證結果為:
- >> A*x-B
- ans =
- 0 0 0
- 0 0 0
- 0 0 0
- >> norm(A*x-B)
- ans =
- 0
運行錯誤通常很難發現,用戶在分析問題時要做到非常細心,並且有時需要做必要的驗證。
異常的錯誤往往出現在規模較大的MATLAB程序中,並且涉及多個函數的調研以及數據的調用,異常的種類也很多,例如,被調用的文件不存在、數據傳輸路徑錯誤、異常的數據輸入等。
3.8.1 MATLAB程序調試方法和過程(2)
2.調試工具
MATLAB提供了大量的調試函數供用戶使用,這些函數可以通過help指令獲得,在MATLAB命令執行窗口輸入如下指令:
- >> help debug
用戶便可獲得這些函數,這些函數都有一個特點,就是以"db"開頭,具體功能和作用如下:
- dbstop - Set breakpoint %設置斷點
- dbclear - Remove breakpoint %清除斷點
- dbcont - Resume execution %重新執行
- dbdown - Change local workspace context %下移本地工作空間內容
- dbmex - Enable MEX-file debugging %使MEX文件調試有效
- dbstack - List who called whom %列出函數調用關系
- dbstatus - List all breakpoints %列出所有斷點
- dbstep - Execute one or more lines %單步或多步執行
- dbtype - List M-file with line numbers %列出M文件
- dbup - Change local workspace context %上移本地工作空間內容
- dbquit - Quit debug mode %退出調試模式
在MATLAB中,這些調試函數都有相應的圖形化調試工具,使得程序的調試更加方便、快捷。這些圖形化調試工具在MATLAB編譯器的"debug"和"Breakpoints"菜單中,以方便調試使用。
3.調試方法
對於簡單的MATLAB程序中出現的語法錯誤,可以采用直接調試法,即直接運行該M文件,MATLAB將直接找出語法錯誤的類型和出現的地方,根據MATLAB的反饋信息對語法錯誤進行修改。
當M文件很大或M文件中含有復雜的嵌套時,則需要使用MATLAB調試器來對程序進行調試,即使用MATLAB提供的大量調試函數以及與之相對應的圖形化工具。
下面通過一個判斷2000年至2010年間的閏年年份的示例來介紹MATLAB調試器的使用方法。
(1)創建一個leapyear.m的M函數文件,並輸入如下函數代碼程序。
- %程序為判斷2000年至2010年10年間的閏年年份
- %本程序沒有輸入/輸出變量
- %函數的使用格式為leapyear,輸出結果為2000年至2010年10年間的閏年年份
- function leapyear %定義函數leapyear
- for year=2000:2010 %定義循環區間
- sign=1;
- a = rem(year,100); %求year除以100后的剩余數
- b = rem(year,4); %求year除以4后的剩余數
- c = rem(year,400); %求year除以400后的剩余數
- if a =0 %以下根據a、b、c是否為0對標志變量sign進行處理
- signsign=sign-1;
- end
- if b=0
- signsign=sign+1;
- end
- if c=0
- signsign=sign+1;
- end
- if sign=1
- fprintf('%4d \n',year)
- end
- end
(2)運行以上M程序,此時MATLAB命令窗口會給出如下錯誤提示:
- ??? Error: File: leapyear.m Line: 10 Column: 6
- The expression to the left of the equals sign is not a valid target for an assignment.
由錯誤提示可知,在程序的第10行存在語法錯誤,檢測可知if選擇判斷語句中,用戶將"=="寫成了"="。因此將"="改成"==",同時也更改第13、16、19行中的"="為"=="。
3.8.1 MATLAB程序調試方法和過程(3)
(3)程序修改並保存完成后,可直接運行修正后的程序,程序運行結果為:
- 2001
- 2002
- 2003
- 2005
- 2006
- 2007
- 2009
- 2010
顯然,2001年至2010年間不可能每年都是閏年,由此判斷程序存在運行錯誤。
(4)分析原因。可能由於在處理年號是否是100的倍數時,變量sign存在邏輯錯誤。
(5)斷點設置。斷點為MATLAB程序執行時人為設置的中斷點,程序運行至斷點時便自動停止運行,等待用戶的下一步操作。設置斷點只需要用鼠標單擊程序左側的" "使得" "變成紅色的圓點(當存在語法錯誤時圓點顏色為灰色),如圖3.2所示。應該在可能存在邏輯錯誤或需要顯示相關代碼執行數據附近設置斷點,例如,本例中的12、15和18行。如果用戶需要去除斷點,可以再次單擊紅色圓點去除,也可以單擊工具欄中的 工具去除所有斷點。
(6)運行程序。按"F5"鍵或單擊工具欄中的 按鈕執行程序,這時其他調試按鈕將被激活。程序運行至第一個斷點暫停,在斷點右側則出現向右指向的綠色箭頭,如圖3.3所示。
![]() |
圖3.2 斷點標記 |
![]() |
圖3.3 程序運行至斷點處暫停 |
程序調試運行時,在MATLAB的命令窗口中將顯示如下內容:
- K>>
此時可以輸入一些調試指令,更加方便對程序調試的相關中間變量進行查看。
(7)單步調試。可以通過按"F10"鍵或單擊工具欄中相應的單步執行圖形按鈕,此時程序將一步一步按照用戶需求向下執行,如圖3.4所示。
(8)查看中間變量。可以將鼠標停留在某個變量上,MATLAB將會自動顯示該變量的當前值,也可以在MATLAB的workspace中直接查看所有中間變量的當前值,如圖3.5所示。
![]() |
圖3.4 程序單步執行 |
![]() |
圖3.5 中間變量查看 |
3.8.1 MATLAB程序調試方法和過程(4)
(9)修正代碼。通過查看中間變量可知,在任何情況下sign的值都是1,此時調整修改代碼程序如下所示。
- %程序為判斷2000年至2010年10年間的閏年年份
- %本程序沒有輸入/輸出變量
- %函數的使用格式為leapyear,輸出結果為2000年至2010年10年間的閏年年份
- function leapyear
- for year=2000:2010
- sign=0;
- a = rem(year,400);
- b = rem(year,4);
- c = rem(year,100);
- if a ==0
- signsign=sign+1;
- end
- if b==0
- signsign=sign+1;
- end
- if c==0
- signsign=sign-1;
- end
- if sign==1
- fprintf('%4d \n',year)
- end
- end
按"F5"鍵再次執行程序,得到的運行結果如下:
- 2000
- 2004
- 2008
分析發現,結果正確,此時程序調試結束。