
使用者定义函式.ppt
35页使用者定義函式 黃聰明 國立臺灣師範大學數學系 min@ntnu.edu.tw http://math.ntnu.edu.tw/~min使用函式的效益•個別測試子任務•程式碼能重複使用Ø 減少整個程式開發所需要的時間與心力Ø 簡化程式的除錯工作•避免無心的錯誤Ø函式從擁有一連串資料(輸入引數清單)的程式中,接收所需的輸入資料,並經由輸出引數清單傳回結果給程式Ø每個函式都擁有自己的獨立變數,並且在自己的工作區內執行,與其他的函式及所呼叫的程式無關Ø在呼叫函式中唯一可以被函式看見的變數,只有這些輸入引數,而函式中唯一能被呼叫程式看見的變數,也只有輸出引數Ø某一函式不小心犯下的程式錯誤,只會影響到此函式內的變數,不會影響整個程式工作區內的變數使用者定義函式T.-M.Huang15-1 MATLAB 函式介紹使用者定義函式T.-M.Huang2function [out1, out2, ...] = funname(in1, in2, ...) statements 函式名稱輸出引數輸入引數儲存之檔案名稱須與函式名稱一樣計算點((x1,y1))與點((x2,y2))的距離使用者定義函式T.-M.Huang3function distance = dist2(x1, y1, x2, y2)%DIST2 Calculate the distance between two points% Function DIST2 calculates the distance between % two points (x1,y1) and (x2,y2) in a Cartesian% coordinate system.%% Calling sequence:% distance = dist2(x1, y1, x2, y2) % Define variables:% x1 -- x-position of point 1% y1 -- y-position of point 1% x2 -- x-position of point 2% y2 -- y-position of point 2% distance -- Distance between points % Calculate distance.distance = sqrt((x2-x1).^2 + (y2-y1).^2); end % function dist2儲存之檔案名稱為 dist2.mH1 comment line>> lookfor distanceDIST2 Calculate the distance between two points>> help dist2 DIST2 Calculate the distance between two points Function DIST2 calculates the distance between two points (x1,y1) and (x2,y2) in a Cartesian coordinate system. Calling sequence: distance = dist2(x1, y1, x2, y2) 呼叫 dist2使用者定義函式T.-M.Huang4% Get input data.disp('Calculate the distance between two points:');ax = input('Enter x value of point a: ');ay = input('Enter y value of point a: ');bx = input('Enter x value of point b: ');by = input('Enter y value of point b: '); % Evaluate functionresult = dist2 (ax, ay, bx, by); % Write out result.fprintf('The distance between points a and b is %f\n',result);function distance = dist2(x1, y1, x2, y2)在函式呼叫之前的工作區使用者定義函式T.-M.Huang5在函式呼叫期間的工作區使用者定義函式T.-M.Huang6在函式呼叫之後的工作區使用者定義函式T.-M.Huang75-2 MATLAB的變數傳遞方式:: 按值傳遞使用者定義函式T.-M.Huang8MATLAB程式使用pass-by-value的方式,進行程式與函式間的溝通聯絡,當程式呼叫函式時,MATLAB便複製實質引數,並傳遞這些實質引數的備份提供函式使用。
使用者定義函式T.-M.Huang9function out = sample(a, b)function out = sample(a, b)fprintf('In sample: a = %f, b = %f %f\n',a,b);fprintf('In sample: a = %f, b = %f %f\n',a,b);a = b(1) + 2*a;a = b(1) + 2*a;b = a .* b;b = a .* b;out = a + b(1);out = a + b(1);fprintf('In sample: a = %f, b = %f %f\n',a,b);fprintf('In sample: a = %f, b = %f %f\n',a,b);輸入引數值改變a = 2; b = [6 4];fprintf('Before sample: a = %f, b = %f %f\n',a,b);out = sample(a,b);fprintf('After sample: a = %f, b = %f %f\n',a,b);fprintf('After sample: out = %f\n',out);>> test_sampleBefore sample: a = 2.000000, b = 6.000000 4.000000In sample: a = 2.000000, b = 6.000000 4.000000In sample: a = 10.000000, b = 60.000000 40.000000After sample: a = 2.000000, b = 6.000000 4.000000After sample: out = 70.000000範例::資料排序((由小到大))使用者定義函式T.-M.Huang10程 式 要 求使用者定義函式T.-M.Huang11使用者輸入任意數量的資料以遞增的順序來排序資料輸出排序過的資料使用者定義函式T.-M.Huang12function out = ssort(a) % Get the length of the array to sortnvals = size(a,2);% Sort the input arrayfor ii = 1:nvals-1 % Find the minimum value in a(ii) through a(n) iptr = ii; for jj = ii+1:nvals if a(jj) < a(iptr) iptr = jj; end end % iptr now points to the minimum value, so swap a(iptr) % with a(ii) if ii ~= iptr. if ii ~= iptr temp = a(ii); a(ii) = a(iptr); a(iptr) = temp; endend% Pass data back to callerout = a;使用者定義函式T.-M.Huang13% Prompt for the number of values in the data setnvals = input('Enter number of values to sort: '); % Preallocate arrayarray = zeros(1,nvals); % Get input valuesfor ii = 1:nvals % Prompt for next value string = ['Enter value ' int2str(ii) ': ']; array(ii) = input(string); End% Now sort the datasorted = ssort(array); % Display the sorted result.fprintf('\nSorted data:\n');for ii = 1:nvals fprintf(' %8.4f\n',sorted(ii));end>> test_ssortEnter number of values to sort: 6Enter value 1: -5Enter value 2: 4Enter value 3: -2Enter value 4: 3Enter value 5: -2Enter value 6: 0Sorted data: -5.0000 -2.0000 -2.0000 0.0000 3.0000 4.00005-3 選擇性的引數使用者定義函式T.-M.Huang14narginnargin::決定函式實際輸入變數的個數決定函式實際輸入變數的個數nargoutnargout::決定函式實際輸出變數的個數決定函式實際輸出變數的個數nargchknargchk::假如用來呼叫函式的引數太少或太假如用來呼叫函式的引數太少或太 多多,,這個函式將傳回一個標準的錯這個函式將傳回一個標準的錯 誤訊息誤訊息errorerror::顯示錯誤的訊息顯示錯誤的訊息,,並放棄執行產生錯並放棄執行產生錯 誤的函式誤的函式warningwarning::顯示警告的訊息顯示警告的訊息,,並繼續執行函式並繼續執行函式使 用 語 法使用者定義函式T.-M.Huang15message = nargchk(min_args, max_args, num_args); 引數的最小數目引數的最大數目實際引數的數目error(‘msg’); 錯誤訊息的字元字串錯誤訊息的字元字串可與可與nargchknargchk互相搭互相搭配配,,當程式發生錯誤當程式發生錯誤時時,,便會產生一個錯便會產生一個錯誤訊息誤訊息warning(‘msg’); 範例使用者定義函式T.-M.Huang16輸入直角座標(x,y),轉換成極座標 輸出如果只輸入一個引數,則函式假設y值為0如果呼叫此函式的敘述式只有一個輸出引數,則傳回距離值angle : angle in degreeangle : angle in degreemag :magnitudemag :magnitudeif if narginnargin < 2< 2 y = 0; y = 0;endendif nargout == 2if nargout == 2 angle = atan2(y,x) * 180 / pi; angle = atan2(y,x) * 180 / pi;endend使用者定義函式T.-M.Huang17function [mag, angle] = polar_value(x,y)%POLAR_VALUE Converts (x,y) to (r,theta)% Check for a legal number of input arguments.narginchk(1,2); % If the y argument is missing, set it to 0.if nargin < 2 y = 0;end% a warning message.if x == 0 & y == 0 msg = 'Both x and y are zero: angle is meaningless!'; warning(msg);end% Now calculate the magnitude.mag = sqrt(x.^2 + y.^2);% If the second output argument is present, calculate % angle in degrees.if nargout == 2 angle = atan2(y,x) * 180/pi;end>> [mag angle] = polar_value??? Error using ==> polar_valueNot enough input arguments.>> [mag angle] = polar_value(1,-1,1)??? Error using ==> polar_valueToo many input arguments.>> [mag angle] = polar_value(1)mag = 1angle = 0>> [mag angle] = polar_value(0,0)Warning: Both x and y are zero: angle is meaningless!> In polar_value at 32mag = 0angle = 0>> [mag angle] = polar_value(1,-1)mag = 1.4142angle = -455-4 使用共用記憶體分享資料使用者定義函式T.-M.Huang18global var1 var2 var3…存放在共用記憶體內的變數• •共用記憶體共用記憶體(Global memory)(Global memory)是一種特別型態的記憶體是一種特別型態的記憶體,,能能在任何的工作區內存取在任何的工作區內存取• •如果一個變數在函式中被宣告為全域變數如果一個變數在函式中被宣告為全域變數,,則這個變數將則這個變數將被存放在共用記憶體內被存放在共用記憶體內,,而不會存放在局部的工作區而不會存放在局部的工作區。
• •如果在另一個函式中有相同名稱的變數被宣告為全域變數如果在另一個函式中有相同名稱的變數被宣告為全域變數,,則這個變數也將對應到與第一個函式中變數相同的記憶體則這個變數也將對應到與第一個函式中變數相同的記憶體位址位址 全域變數的使用原則使用者定義函式T.-M.Huang191.盡量少用全域變數 全域變數使程式的流程不透明全域變數使程式的流程不透明,,造成程式除錯或維護的困造成程式除錯或維護的困 難難2.使用全域變數,,請遵循下列兩原則 ((1 1))使用前一定要宣告使用前一定要宣告 ((2 2))使用全部大寫或較長的變數名稱使用全部大寫或較長的變數名稱,,以資區別以資區別3.檢視工作空間的變數,,輸入whos global4.清除所有工作空間的全域變數 X,,需使用 clear global X範例::亂數產生器使用者定義函式T.-M.Huang20 Modulo functionModulo function:::: 是非負整數是非負整數產生一個介於0到134455的數列若未知8121,, 28411及134456,,則無法猜測此數列每個產生的數字出現在數列的機率均相等(均勻分佈)使用者定義函式T.-M.Huang21 利用modulo function來設計一個亂數產生器,,以輸出在[0, 1)範圍的實數問題問題方法方法要求要求給予modulo function之初始值 以下列方式產生介於0與1之間的實數:函式能夠產生並回傳亂數數列的陣列函式必須有一個或兩個輸入引數(n及m),用以設定傳回的陣列大小。
如果只有一個引數,函式傳回 的陣列如果有兩個引數,函式傳回 的陣列亂數之初始值 ,由另一函式來指定使用者定義函式T.-M.Huang22function ran = random0(n,m)%RANDOM0 Generate uniform random numbers in [0,1) % Declare global valuesglobal ISEED % Seed for random number generator % Check for a legal number of input arguments.narginchk(1,2); % If the m argument is missing, set it to n.if nargin < 2 m = n;end % Initialize the output arrayran = zeros(n,m); % Now calculate random valuesfor ii = 1:n for jj = 1:m ISEED = mod(8121*ISEED + 28411, 134456 ); ran(ii,jj) = ISEED / 134456; endendfunction seed(new_seed) % Declare global valuesglobal ISEED msg = nargchk(1,1,nargin);error(msg); % Save seednew_seed = round(new_seed);ISEED = abs(new_seed);測試結果使用者定義函式T.-M.Huang23>> seed(1024)>> random0(4)ans = 0.0598 1.0000 0.0905 0.2060 0.2620 0.6432 0.6325 0.8392 0.6278 0.5463 0.7551 0.4554 0.3177 0.9105 0.1289 0.6230>> ISEED??? Undefined function or variable 'ISEED'.>> random0(4)ans = 0.2266 0.3858 0.5876 0.7880 0.8415 0.9287 0.9855 0.1314 0.0982 0.6585 0.0543 0.4256 0.2387 0.7153 0.2606 0.89225-6 含函式的函式使用者定義函式T.-M.Huang24是一種輸入引數包含其他函式名稱的函式,,而這些傳入函式名稱的函式,,會在含函式的函式執行過程中,,被呼叫來使用。
fzerofzero::內建函式內建函式,,找出只含一個變數函式之零點找出只含一個變數函式之零點>> fzero('cos',[0 pi])ans = 1.5708>> fzero(@(x)exp_2(x),[0 pi])ans = 0.6931function val = exp_2(x)val = exp(x) - 2;>> fzero( @exp_2,[0 pi] )ans = 0.6931>> fzero('exp_2' ,[0 pi] )ans = 0.6931內建函式 eval使用者定義函式T.-M.Huang25eval(string)eval(string)eval 會針對string字元字串求值>> x= 1;>> str = ['exp(' num2str(x) ') - 1'];>> res = eval(str)res = 1.7183for d=1:10 s = ['load August' int2str(d) '.mat'] eval(s)end>> x = eval('sin(pi/4)')x = 0.7071s = load August1.mats = load August2.mats = load August3.mat - etc. -使用者定義函式T.-M.Huang26內建函式 fevalfeval(fun,value)feval(fun,value)feval 會針對M檔案中的(fun)函式,,在特定輸入值(value)下計算其函式值>> feval('sin',pi/4)ans = 0.7071>> feval('exp_2' , 0)ans = -1>> feval( @exp_2, 0)ans = -1function val = exp_2(x)val = exp(x) - 2;>> feval(@(x)exp_2(x), 0)ans = -1使用者定義函式T.-M.Huang27範例問題問題要求要求步驟步驟在特定的數值區間,,產生一個含函式的函式,,用來畫出任一個MATLAB單一變數的函式圖形。
函式需要兩個輸入引數第一個引數為被畫出圖形的函式名稱第二個引數為兩個元素的向量,此為函式圖形的範圍檢查合法的引數個數檢查第二個引數是否擁有兩個元素在初始點與結束點之間,計算函式的數值繪圖並標示函式圖形msg = nargchk(2,2,nargin);error(msg);if ( size(xlim,1) == 1 && … size(xlim,2) == 2 ) || ... ( size(xlim,1) == 2 && … size(xlim,2) == 1 ) statementselse error('Incorrect number of elements in xlim.');end使用者定義函式T.-M.Huang28function quickplot(fun,xlim)%QUICKPLOT Generate quick plot of a function % Check for a legal number of input arguments.narginchk(2,2); % Check the second argument to see if it has two elements. if ( size(xlim,1) == 1 && size(xlim,2) == 2 ) || ... ( size(xlim,1) == 2 && size(xlim,2) == 1 ) n_steps = 100; step_size = (xlim(2) - xlim(1)) / n_steps; x = xlim(1):step_size:xlim(2); y = feval(fun,x); plot(x,y); title(['\bfPlot of function ' fun '(x)']); xlabel('\bfx'); ylabel(['\bf' fun '(x)']);else error('Incorrect number of elements in xlim.');end>> quickplot('sin')Error using quickplot (line 5)Not enough input arguments.>> quickplot('sin', -2*pi)Error using quickplot (line 19)Incorrect number of elements in xlim.>> quickplot('sin', [-2*pi 2*pi])5-7 子函式、、專用函式與巢狀函式使用者定義函式T.-M.Huang29一個一個MM檔案可以包含一個以上的函數檔案可以包含一個以上的函數主函數與子函數的位置主函數與子函數的位置一個主函數((Primary Function))其他則為子函數((Subfunctions))主函數必須與檔案名稱一樣子函數只能被同檔案中的函數((主函數或子函數))呼叫,,但不可被不同檔案的其他函數呼叫主函數必需出現在最上方其後接上任意數目的子函數子函數的次序並無任何限制使用者定義函式T.-M.Huang30圖例私有化目錄((Private Directory))使用者定義函式T.-M.Huang31在目錄中建立名稱為 private 的私有化目錄存放與這目錄相關的函數目錄 private 之下的函數,,只能被其父目錄函數所呼叫,,不能被其他目錄的函數來呼叫函 數 搜 尋 次 序使用者定義函式T.-M.Huang32從 M 檔案呼叫一個函數時,,MATLAB 搜尋函數的次序檢查此函數是否為子函數檢查此函數是否為私有化目錄的函數從系統所設定的搜尋路徑找尋此函數MATLAB 找到第一個檔名相符的函數,,即會立即取用巢 狀 函 式使用者定義函式T.-M.Huang33圖例NEEDNEED使用者定義函式T.-M.Huang34function res = test_nested_1% Define some variables.a = 1; b = 2; x = 0; y = 9; % Display variables before call to fun1fprintf('Before call to fun1:\n');fprintf('a, b, x, y = %2d %2d %2d %2d\n', a, b, x, y); % Call nested function fun1x = fun1(x); % Display variables after call to fun1fprintf('\nAfter call to fun1:\n');fprintf('a, b, x, y = %2d %2d %2d %2d\n', a, b, x, y); % Declare a nested function function res = fun1(y) % Display variables at start of call to fun1 fprintf('\nAt start of call to fun1:\n'); fprintf('a, b, x, y = %2d %2d %2d %2d\n', a, b, x, y); y = y + 5; a = a + 1; res = y; % Display variables at end of call to fun1 fprintf('\nAt end of call to fun1:\n'); fprintf('a, b, x, y = %2d %2d %2d %2d\n', a, b, x, y); end % function fun1end % function test_nested_1>> test_nested_1Before call to fun1:a, b, x, y = 1 2 0 9At start of call to fun1:a, b, x, y = 1 2 0 0At end of call to fun1:a, b, x, y = 2 2 0 5After call to fun1:a, b, x, y = 2 2 5 9。
