跳轉到內容

MATLAB 程式設計/錯誤訊息

來自華夏公益教科書,開放的書籍,開放的世界



據我所知,很少有資料可以幫助人們解讀 MATLAB 的錯誤訊息。大多數語法錯誤一旦你知道原因就不難修復,因此本指南旨在幫助識別和修復 MATLAB 程式碼中的錯誤。

警告也在這裡顯示,因為它們通常會導致以後出現錯誤。

算術錯誤

[編輯 | 編輯原始碼]

通常這些是自我解釋的。作為提醒,以下是一些常見的無法執行的函式以及 MATLAB 返回的內容(以及每個函式的警告)

a/0 = Inf if a > 0, -Inf if a < 0, and NaN if a = 0.
log(0) = -Inf
MATLAB defines 0^0 to be 1.

NaN 經常會導致錯誤或無用的結果,除非採取措施避免傳播它們。

???Error using ==> minus
Matrix dimensions must agree.

因此,檢查表示式中所有項的維度。通常是索引錯誤導致項大小不同。如果你使用的是冪函式,你可能會在引數後新增一個點。即 y=x.^2 而不是 y=x^2

矩陣乘法要求第一個矩陣的列數等於第二個矩陣的行數。否則,你會收到以下訊息

??? Error using ==> mtimes
Inner matrix dimensions must agree.

注意此錯誤與上一個錯誤的區別。此錯誤通常發生是因為索引問題,或者因為你打算使用逐元素乘法,但忘記了點。

嘗試對奇異矩陣求逆將導致警告和一個 Inf 矩陣。在嘗試求逆之前明智的做法是計算行列式,或者更好的是,使用不需要求逆的方法,因為求逆在數值上不穩定。

嘗試對非方陣求冪將導致以下錯誤

??? Error using ==> mpower
Matrix must be square.

這通常是因為你打算使用逐元素求冪,但忘記了點。

陣列索引錯誤

[編輯 | 編輯原始碼]

陣列索引是 MATLAB 的關鍵組成部分。一項功能是變數和函式的名稱區分大小寫,並且可以將內建或使用者編寫的函式與相同名稱的變數別名。因此,如果你建立一個名為 abs 的陣列,並嘗試呼叫函式 abs(1),MATLAB 將返回陣列 abs 中的第一個值,而不是值 1。MATLAB 不會為此返回錯誤,因為它無法確定函式的別名是否為有意為之。因此,永遠不要將你的變數命名為與現有 MATLAB 函式相同。不幸的是,基礎產品加上已安裝的工具箱中有如此多的提供函式,記住所有這些是不可能的,所以如果你有任何疑問,該名稱可能在定義新陣列或函式之前已經使用過,請使用which proposedname。較新版本的 MATLAB 具有命令完成功能,將在開啟括號或製表符完成選項後顯示簡短的幫助資訊,使用該功能將有助於在執行過程中避免此類錯誤,因為不會在以後建立別名。

有些事情是相當明顯的,但需要一些實踐來避免

你無法嘗試訪問尚未存在的陣列部分。

>> A = [1,3];
>> A(3)
??? Index exceeds matrix dimensions.

不幸的是,如果有多個變數,MATLAB 不會告訴你超過維度的哪個變數,所以你必須檢查它。例如,如果你使用迴圈來更改訪問陣列的哪一部分,但迴圈沒有在到達陣列末尾之前停止,就會經常發生這種情況。如果你最終得到一個空矩陣作為某個操作的結果,然後嘗試訪問其中的元素,也會發生這種情況。

你無法嘗試訪問陣列的負數、複數、非整數或零部分;如果你這樣做,你會收到以下訊息

>> A(-1)
>> A(i)
>> A(1.5)
>> A(0)
??? Subscript indices must either be real positive integers or logicals.

注意,MATLAB 陣列是基於 1 的,而不是基於 0 的,並且是固定低維度的,而不是可變的。MATLAB 可能會根據上下文告訴你哪個索引不是實數或邏輯值。

 >> y=3*A(-1)
Attempted to access A(-1); index must be a positive integer or logical. 

後者是一個表示式,解析方式不同,因此在錯誤訊息中具有實際的陣列。

還要注意,如果 0 是一個邏輯 0(假),那麼語句 A(0) 將不是索引錯誤,而是一個邏輯下標表達式。在這種情況下,返回值將是空[]陣列,因為在已定義的 [1 2] 集合中沒有匹配假的下標,因為 A 已經在上面定義了。一個更有用的表示式類似於

>> A(A==3)

嘗試在你的索引中使用非標準 MATLAB 語法,通常會導致以下錯誤

>> A(2::, 2)
??? A(2::, 2)
        |
Error: Unexpected MATLAB operator.

上面的程式碼可能是試圖訪問 A 的第一個之後的所有行和第二列,在這種情況下,你應該使用“end”語法,例如

>> A(2:end, 2)
ans = 3

賦值錯誤

[編輯 | 編輯原始碼]

啊,賦值,就是使用 = 符號為變數或陣列的某些元素賦予特定值。

讓我們從一個經典的錯誤開始

>> a = 2;
>> if a = 3
??? if a = 3
         |
Error: The expression to the left of the equals sign is not a valid target for an assignment.

此錯誤發生是因為你本來是想檢視“a”是否等於 3,但你告訴 MATLAB 將“a”的值設定為 3。你不能在 if/while 語句所在同一行上執行此操作。正確的語法是

>> if a == 3
>> end

這不會產生任何錯誤(並且你可以在條件中放入你想要的任何內容)。

你不能在普通陣列中包含兩種不同類別的資料。例如,

>> A = @(T) (1+T)
A = 
   @(T) (1+T)
>> A(2) = 3
??? Conversion to function_handle from double is not possible.

為此目的,你應該使用元胞陣列或結構體陣列。

這是最棘手的。看看下面的程式碼

>> A = [1,2,3;4,5,6;7,8,9];
>> A(2,:) = [3,5];
??? Subscripted assignment dimension mismatch.
>> A(2,:) = [1,4,5,6];
??? Subscripted assignment dimension mismatch.
>> A(1:2, 1:2) = [1,2,3,4];
??? Subscripted assignment dimension mismatch.

這裡發生了什麼?在這三個例子中,都看看左右兩邊的維度。在第一個例子中,左邊是一個 1x3 陣列,但右邊是一個 1x2 陣列。在第二個例子中,左邊是 1x3,而右邊是 1x4。最後,在第三個例子中,左邊是 2x2,而右邊是 1x4。在這三個例子中,維度不匹配。如果你想替換現有變數的特定部分,它們必須匹配。並不重要,只要它們具有相同數量的資料點(如第三個例子所示);維度也必須相同,例外是如果你在一側有一個 1xn 陣列,而在另一側有一個 nx1 陣列,MATLAB 將自動轉置併為你替換

>> A(2,:) = [1;2;3]
A =   1     2     3
      1     2     3
      7     8     9

如果你不希望這樣,請注意它!

結構體陣列錯誤

[編輯 | 編輯原始碼]

結構體陣列相當複雜,它們對你可以做和不能做的事情有一套嚴格的規則。讓我們首先處理結構體陣列中的索引。假設你定義變數“cube”,並希望在一個結構體陣列中儲存兩個不同立方體的體積和一側的長度。這可以透過以下方式完成

>> cube(1).side = 1;
>> cube(1).volume = 1;
>> cube(2).side = 2;
>> cube(2).volume = 8;

這似乎是儲存資料的不錯方法,而且對於某些目的來說確實如此。但是,假設你想要從結構體中提取體積並將它們儲存在一個數組中。你無法以這種方式執行此操作

>> volumes = cube.volume
??? Illegal right hand side in assignment. Too many elements.

你會注意到,如果你告訴 MATLAB 顯示cube.volume,它會顯示這兩個值,但在每次重新分配變數ans,因為它被視為兩個單獨的變數。為了避免錯誤,你必須在賦值時將 'cube.volume' 格式化為陣列。

>> volumes = {cube.volume}

你也可以為每個立方體編寫一個單獨的賦值,但這更適合數量較多的立方體。

就像提取資料一樣,你必須一次輸入一個數據,即使它對根的所有例項(立方體)都是相同的。

>> cube.volForm = @(S) (S^3)
??? Incorrect number of right hand side elements in dot name assignment.  Missing [] around left hand side is a likely cause.
>> cube(:).volForm = @(S) (S^3)
??? Insufficient outputs from right hand side to satisfy comma separated
list expansion on left hand side.  Missing [] are the most likely cause.

不幸的是,缺少 [] 不是原因,因為新增它們會導致更多錯誤。原因是,你不能將同一個值一次分配給所有具有相同名稱的欄位,你必須一次一個地執行此操作,如以下程式碼所示

>> for ii = 1:2
>>   cube(ii).volForm = @(S) (S^3);
>> end
>> cube
ans = 1x2 struct array with fields:
  volume
  side
  volForm

然後,在兩個立方體中都找到了相同的體積公式。如果你不拆分根,這個問題就可以得到緩解,強烈建議這樣做。例如,你可以使用這樣的結構體

>> shapes.cubeVol = @(S) (S^3);
>> shapes.cube(1).vol = 1;
>> shapes.cube(2).vol = 8;

這樣可以避免使用迴圈來輸入對所有立方體都通用的公式。

語法錯誤

[編輯 | 編輯原始碼]

括號錯誤

[編輯 | 編輯原始碼]

與 C++ 不同,您不需要在每行程式碼的末尾新增任何東西,只需要換行符。但是,您仍然需要遵循語法規則。在 MATLAB 中,您必須格外小心地放置括號,以確保 MATLAB 能夠按照您的意願執行操作。

以下示例展示了一個非常常見的錯誤

>> A(1
??? A(1
       |
Error: Expression or statement is incorrect--possibly unbalanced (, {, or [.

這個錯誤很簡單,意味著您缺少一個括號,或者括號過多。另一個密切相關的錯誤如下

>> A(1))
??? A(1))
        |
Error: Unbalanced or misused parentheses or brackets.

MATLAB 會嘗試告訴您缺少的括號應該放在哪裡,但它並不總是正確。因此,對於複雜的表示式,您必須仔細檢查才能找到您的拼寫錯誤。一個有用的技巧是嘗試在出錯行之後設定一個斷點。在糾正錯誤之前,它不會變紅,因此請不斷嘗試糾正錯誤並儲存檔案,直到該斷點變紅。當然,之後您必須確保括號的放置合理,否則您可能會遇到其他與無效索引或無效函式呼叫相關的錯誤。

字串錯誤

[編輯 | 編輯原始碼]

您可以透過兩種方式建立字串:使用 '字串' 語法,或者在兩個詞之間只新增空格(不包括換行符),例如

>> save file.txt variable

在這行程式碼中,file.txtvariable 被作為字串傳遞給 save 函式。偶爾會忘記括號,並意外地嘗試將字串傳遞給不接受字串作為輸入的函式,這會導致錯誤

>> eye 5
??? Error using ==> eye
Only input must be numeric or a valid numeric class name.

這些錯誤應該很容易發現,因為字串是用紫色顏色編碼的。如果取消註釋一行文字並忘記更改它,就會發生這種情況。

在另一種字串語法中,忘記關閉 ' 會導致明顯的錯誤

>> A = 'hi
??? A = 'hi
        |
Error: A MATLAB string constant is not terminated properly.

未終止的字串用紅色顏色編碼,以便讓您知道它沒有終止,因為很容易忘記。

使用字串時,一個常見的錯誤是嘗試使用 '==' 運算子比較它們。如果字串的長度不同,這將不起作用,因為字串是字元陣列,要使用 '==' 比較陣列,它們的大小必須相同。要比較兩個字串,必須使用strcmp 函式

>> 'AA' == 'AaA'
??? Error using ==> eq
Matrix dimensions must agree.
>> strcmp('AA', 'AaA')
ans = 0
>> strcmp('A', 'a')
ans = 0
>> strcmp('AA', 'AA')
ans = 1

請注意,MATLAB 字串區分大小寫,'A' 和 'a' 不是同一個字串。

還要注意,用於開始和結束字串的 ' 字元與表示轉置的字元相同。因此,如果您關閉一個字串而沒有開啟它,您很可能會收到關於未定義變數的錯誤(如果您嘗試轉置一個未定義的變數),或者只是得到非常奇怪的結果,因為您轉置了您不想轉置的內容。

其他雜項錯誤

[編輯 | 編輯原始碼]

您不能保留尾隨函式,如果您這樣做,MATLAB 會給您一個類似但並非完全相同的錯誤,因為缺少括號,因為它不想冒險猜測

>> A = 1+3+
??? A = 1+3+
            |
Error: Expression or statement is incomplete or incorrect.

這些錯誤通常很容易發現,並且通常是由於忘記了用於拆分行的 "..." 造成的。

雙冒號不是唯一的“意外 MATLAB 運算子”,還有“..”、“....”以及其他幾個會導致此錯誤的拼寫錯誤。

如果您意外地鍵入了 ` 字元,您會收到以下錯誤

>> ??? `
       |
Error: The input character is not valid in MATLAB statements or expressions.

這通常是因為您打算在方程式中輸入“1”,但按錯了鍵。另一種可能是您使用計算機不常用的字母命名您的 m 檔案。例如,在德國,“ä, ü 或 ö”。請確保您的 m 檔案只使用常見的字母,並且不要使用大寫字母。

函式呼叫錯誤

[編輯 | 編輯原始碼]

您很有可能嘗試呼叫一個不存在的函式,例如

>> samplemat = [1 2; 1 4]
>> A = eigen(samplemat);
??? Undefined command/function 'eigen'.

這可能是因為您不知道執行預期操作的函式的名稱(例如,如果您想計算矩陣“samplemat”的特徵值,您想呼叫 eig,而不是 eigen)。開啟 MATLAB 的幫助(轉到幫助 -> 產品幫助或在命令提示符中鍵入 doc)並搜尋您想要的操作通常很有用。

如果您嘗試呼叫建立的函式,但收到此錯誤,可能有幾個原因

  1. m 檔案必須位於檔案 -> 設定路徑中列出的路徑之一中,或者必須位於您的當前目錄中
  2. m 檔案的名稱必須與函式宣告中的名稱相同。您必須特別注意這一點,尤其是當您更改函式的名稱時,您還必須更改檔案的名稱,否則 MATLAB 找不到正確的函式!

如果 MATLAB 找到了函式,它將嘗試執行它。但是,在呼叫函式時,有幾個潛在的陷阱需要避免。為了呼叫函式,您需要了解給定函式的輸入和輸出引數的性質。對於 MATLAB 的內建函式,此資訊可在文件中找到,或者透過鍵入

>> help functionname

最好設定一些註釋,以便幫助函式也能讀取您自己的程式碼中的註釋,這樣您就可以快速參考所有函式的工作原理以及它們的作用。為此,請注意,幫助函式只讀取函式宣告下方的註釋塊,因此,例如,如果您編寫這樣的函式

function outvars = myfunc(invars)
% function outvars = myfunc(invars)
% Outputs outvars
% All of this is outputted when you type >> help myfunc 

% But this wouldn't be

將函式儲存為“myfunc.m”,然後鍵入

>> help myfunc

它將輸出

>> function outvars = myfunc(invars)
Outputs outvars
All of this is outputted when you type >> help myfunc

大多數函式(但並非所有函式)都需要至少一個輸入引數,如果使用過少的引數呼叫它,將導致錯誤

>> A = ode45()
??? Error using ==> ode45
Not enough input arguments.  See ODE45.

您也不能使用過多的輸入引數呼叫函式

>> A = plus(1,2,3)
??? Error using ==> plus
Too many input arguments.

輸入引數必須採用函式期望的格式。這將非常特定於函式,因此請檢視文件或幫助以瞭解有關它們期望的詳細資訊。例如,ODE45 和其他 ODE 求解器中的第一個引數必須是函式控制代碼;如果您以錯誤的順序傳遞引數,您將收到一條關於此錯誤的資訊。

您可以使用方括號符號選擇想要從可用輸出引數中獲取的輸出引數數量。您可以選擇儲存比函式提供的更少的輸出引數,但您不能分配比函式能輸出的引數更多的變數

>> A = [1,2;3,4]
D = eig(A); %one output argument
[V,D] = eig(A); %two output arguments
[V,D,Mistake] = eig(A);
??? Error using ==> eig
Too many output arguments.

如果您要替換已存在陣列的部分內容,則所有分配的輸出引數也必須具有正確的類(有關此內容的更多資訊,請參閱關於賦值的部分)。如果您使用輸出建立新變數,這不是問題。

控制流錯誤

[編輯 | 編輯原始碼]

迄今為止最常見的一個是,如果您忘記了 'END',這是 M 檔案函式中的一個問題。它會告訴您“至少缺少一個 END”,並嘗試告訴您迴圈或條件語句從哪裡開始。

如果您有太多 END 語句,並且在同一個 M 檔案中有多個函式,MATLAB 可能會給您一個關於函式格式不正確的模糊訊息。這是因為同一個 M 檔案中的所有函式必須都以 END 語句結束,或者都不以 END 語句結束。這無關緊要,但是如果您在一個函式中有很多 END 語句,MATLAB 會認為您的函式提前結束了,並且當下一行中的下一個函式在末尾沒有 END 語句時,它會感到困惑。因此,如果您收到此令人困惑的訊息,請查詢額外的 END 語句,它應該可以解決您的問題。如果在釋出時顯示該訊息(例如釋出到 HTML 檔案),則問題可能是層次結構縮排不規則。嘗試選擇所有內容,然後按 cntrl-i 以進行自動縮排,以解決問題。

在 'switch' 語句中有一個額外的 END 會導致一條訊息,指出您非法使用了 'case' 關鍵字,因為 MATLAB 認為您提前結束了 switch 語句,並且 'case' 在 'switch' 語句之外沒有意義。

其他錯誤

[編輯 | 編輯原始碼]

有許多型別的錯誤不會從 MATLAB 編譯器生成錯誤,這些錯誤與呼叫錯誤的函式、使用錯誤的操作、使用錯誤的變數、引入無限迴圈等有關。這些錯誤將是最難修復的,但藉助 MATLAB 偵錯程式,將更容易找到它們。有關如何使用偵錯程式的詳細資訊,請參閱除錯 M 檔案

檢測或計劃錯誤

[編輯 | 編輯原始碼]

無論程式碼多麼精確,錯誤都可能發生。使用除錯技術可以提供很大幫助,但計劃錯誤或預計錯誤也同樣寶貴。這包括建立一個可能不需要的 if 塊來決定要做什麼。例如,如果 x < 5 就執行操作 A,如果 x > 5 就執行操作 B。另外,在大型迴圈中新增一個帶模運算子的 if 塊,例如:if not ( mod ( ii , 5 ) ) % 執行操作; end。這樣,迴圈只會在 ii 計數器可以被 5 整除時執行測試。一些語法錯誤或邏輯錯誤會在迴圈執行很長時間後發生,如果發生錯誤,就會顯示錯誤資訊,解釋錯誤發生的位置,但不一定說明錯誤發生的原因。例如,向量 x 比向量 y 少一個元素,而 x .* y 無法執行。這種錯誤通常發生在最短向量的最後一個元素上,除非採取措施,否則很難發現。try % 執行操作; catch me me.getReport; 在這種情況下,斷點和 even disp(me.getReport) 都會很有幫助。如果錯誤不是致命的,程式碼甚至可以繼續執行,但會將錯誤顯示為訊息或轉換為警告。

包含的 Matlab 工具/函式:warning, lastwarn, disp, try catch, dbstack, rethrow, throwAsCaller 和 Matlab 關於上述函式的幫助,以發現每種方法的優缺點。

華夏公益教科書