1. 程式人生 > >一般區域二重、三重積分MATLAB計算方法

一般區域二重、三重積分MATLAB計算方法

這裡討論的計算方法指的是利用現有的MATLAB函式來求解,而不是根據具體的數值計算方法來編寫相應程式。目前最新版的2009a有關於一般區域二重積分的計算函式quad2d,但沒有一般區域三重積分的計算函式,而NIT工具箱似乎也沒有一般區域三重積分的計算函式。
本貼的目的是介紹一種在7.X版本MATLAB(不一定是2009a)裡求解一般區域二重三重積分的思路方法。需要說明的是,在MATLAB的dblquad幫助文件裡已經討論了一種求解一般區域二重三重積分的思路方法,就是將被積函式“延拓”到矩形或者長方體區域,但是這種方法不可避免引入很多乘0運算浪費時間。因此,新的思路將避免這些。由於是呼叫已有的MATLAB函式求解,在求一般區域二重積分時,效率和2009a的quad2d相比有一些差距,但是相對於"延拓"函式的做法,效率大大提高了。下面結合一些簡單例子說明下計算方法。

譬如二元函式f(x,y) = x*y,y從sin(x)積分到cos(x),x從1積分到2,這個積分可以很容易用符號積分算出結果
  1. syms x 
  2. y
  3. int(int(x*y,y,sin(x),cos(x)),1,2) ]
  4. 結果是 
  5. -1/2*cos(1)*sin(1)-1/4*cos(1)^2+cos(2)*sin(2)+1/4*cos(2)^2 = 
  6. -0.635412702399943
複製程式碼 如果你用的是2009a,你可以用
  1. quad2d(@(x,y) 
  2. x.*y,1,2,@(x)sin(x),@(x)cos(x),'AbsTol',1e-12)
複製程式碼 得到上述結果。
如果用的不是2009a,那麼你可以利用NIT工具箱裡的quad2dggen函式。

那麼我們如果既沒有NIT工具箱用的也不是2009a,怎麼辦呢?
答案是我們可以利用兩次quadl函式,注意到quadl函式要求積分表示式必須寫成向量化形式,所以我們構造的函式必須能接受向量輸入。見如下程式碼
  1. function 
  2. IntDemo
  3. function f1 = myfun1(x)
  4. f1 = zeros(size(x));
  5. for k = 
  6. 1:length(x)
  7. f1(k) = quadl(@(y) 
  8. x(k)*y,sin(x(k)),cos(x(k)));
  9. end
  10. end
  11. y = 
  12. quadl(@myfun1,1,2)
  13. end
複製程式碼 myfun1函式就是構造的原始被積函式對y積分後的函式,這時候是關於

x的函式,要能接受向量形式的x輸入,所以構造這個函式的時候考慮到x是向量的情況。
利用arrayfun函式(7.X後的版本都有這個函式,不瞭解這個函式的朋友可以檢視幫助文件,或者百度搜索arrayfun)可以將IntDemo函式精簡成一句程式碼:
  1. quadl(@(x) 
  2. arrayfun(@(xx) quadl(@(y) 
  3. xx*y,sin(xx),cos(xx)),x),1,2)
複製程式碼 上面這行程式碼體現了用MATLAB7.X求一般區域二重積分的一般方法。可以這麼理解這句程式碼:
首先
  1. @(x) 
  2. arrayfun(@(xx) quadl(@(y) 
  3. xx*y,sin(xx),cos(xx)),x)
複製程式碼 定義了一個關於x的匿名函式,供quadl呼叫求最外重(x從1到2的)積分,這時候,x對於
  1. arrayfun(@(xx) 
  2. quadl(@(y) xx*y,sin(xx),cos(xx)),x)
複製程式碼 就是已知的了。
  1. @(xx) quadl(@(y) 
  2. xx*y,sin(xx),cos(xx))
複製程式碼 定義的是對於給定的xx,求xx*y關於y的積分函式,這就相當於數學上積完第一重y的積分後得到一個關於xx的函式
  1. arrayfun(@(xx) 
  2. quadl(@(y) xx*y,sin(xx),cos(xx)),x)
複製程式碼 只是對
  1. @(xx) quadl(@(y) 
  2. xx*y,sin(xx),cos(xx))
複製程式碼 加了一個迴圈的殼,保證“積完第一重y的積分後得到一個關於xx的函式”能夠接受向量化的xx的輸入,從而能夠被quadl呼叫。
有了這個模板,我們可以方便求其他一般積分割槽域(上下限是函式)形式的二重積分,例如被積函式

= @(x,y) 
exp(sin(x))*ln(y),y從5*x積分到x^2,x從10積分到20。
用quad2d,上面介紹的方法,還有dblquad幫助文件裡給的延拓函式的方法
  1. tic,y1 
  2. = quad2d(@(x,y) exp(sin(x)).*log(y),10,20,@(x)5*x,@(x)x.^2),toc
  3. tic,y2 = 
  4. quadl(@(x) arrayfun(@(x) quadl(@(y) 
  5. exp(sin(x)).*log(y),5*x,x.^2),x),10,20),toc
  6. tic,y3 = dblquad(@(x,y) 
  7. exp(sin(x)).*log(y).*(y>=5*x & y<=x.^2),10,20,50,400),toc
  8. y1 
  9. =
  10. 9.368671342614414e+003
  11. Elapsed time is 0.021152 seconds.
  12. y2 
  13. =
  14. 9.368671342161189e+003
  15. Elapsed time is 0.276614 seconds.
  16. y3 
  17. =
  18. 9.368671498376889e+003
  19. Elapsed time is 1.674544 
  20. seconds.
複製程式碼 可見上述方法在2009a以外的版本中不失為一種方法,起碼效率高於dblquad幫助文件裡推薦的做法。更重要的是,這給我們求解一般區域三重積分提供了一種途徑。