MATLAB中代码优化的两种方法
MATLAB中的代碼優(yōu)化
MATLAB中的代碼優(yōu)化有兩種重要的方法:預(yù)分配組和向量化循環(huán)。
我們舉一個(gè)簡(jiǎn)單的例子來看,創(chuàng)建一個(gè)MATLAB函數(shù)來計(jì)算f(x) = sin(x / 100π):
function y = sinfun1(M) x = 0: M - 1; for k = 1: numel(x)y(k) = sin(x(k) / (100 * pi)); end這里 我們使用函數(shù)timeit來計(jì)算調(diào)用函數(shù)所需的時(shí)間。(timeit可用于得到函數(shù)調(diào)用的可靠的、可重復(fù)的時(shí)間測(cè)量。)
此時(shí)我們得到M數(shù)量級(jí)為20000時(shí)的時(shí)間測(cè)量,如圖1所示:
圖1 函數(shù)sinfun1在M=20000的時(shí)間測(cè)量我們?cè)诰帉懲旰瘮?shù)sinfun1后可以看到MATLAB編輯器給出了一個(gè)提示:變量’y’似乎會(huì)隨迭代次數(shù)而改變,請(qǐng)預(yù)分配內(nèi)存以獲得更高的運(yùn)算速度。
為什么會(huì)出現(xiàn)這樣的情況?那是因?yàn)樵趕infun1這個(gè)函數(shù)中,輸出變量y每經(jīng)過一次循環(huán)后都會(huì)增長一個(gè)元素大小,它必須重新分配新的存儲(chǔ)空間,并且在每次數(shù)組生長時(shí)都要復(fù)制前一組數(shù)組元素。這種頻繁的內(nèi)存重新分配和復(fù)制的開銷非常大,與sin本身的計(jì)算相比需要更多的時(shí)間。
此時(shí)我們采用預(yù)分配數(shù)組的辦法進(jìn)行嘗試:
預(yù)分配組:是指在進(jìn)入一個(gè)計(jì)算數(shù)組元素的for循環(huán)之前,初始化數(shù)組。預(yù)分配就意味著咋循環(huán)開始之前把它初始化為所希望的輸出大小。
function y = sinfun2(M) x = 0: M - 1; y = zeros(1, numel(x)); for k = 1: numel(x)y(k) = sin(x(k) / (100 * pi)); end在這里我們使用了zeros生成一個(gè)矩陣來預(yù)分配存儲(chǔ)空間,然后調(diào)用timeit計(jì)算M=20000時(shí)候的時(shí)間測(cè)量,如圖2:
圖1 函數(shù)sinfun2在M=20000的時(shí)間測(cè)量通過對(duì)比可以得出,在M=20000的數(shù)量級(jí)下,使用預(yù)分配數(shù)組的辦法,要比不使用運(yùn)行快4倍。
接下來我們?cè)贛的數(shù)量級(jí)為200000和2000000下對(duì)兩種方法進(jìn)行比較,得出的結(jié)果如圖3,圖4所示: 圖3 兩種方法在M=200000下的時(shí)間測(cè)量
圖4 兩種方法在M=2000000下的時(shí)間測(cè)量
我們通過計(jì)算可以得出,函數(shù)sinfun1基本維持了所要求的的時(shí)間與M成正比,sinfun2則在數(shù)量級(jí)到了一定程度后維持正比。另外比較兩個(gè)函數(shù)在200000和2000000下的速度比,可見在這兩個(gè)數(shù)量級(jí)下預(yù)分配數(shù)組的方法大約要比sinfun1快6倍。
向量化循環(huán)是指使用矩陣/向量運(yùn)算符、索引技術(shù)和現(xiàn)有的MATLAB或工具箱函數(shù)來完全消除循環(huán)的一種技術(shù)。
我們使用向量化循環(huán)對(duì)矩陣的輸入進(jìn)行逐元素的操作來消除循環(huán):
function y = sinfun3(M) x = 0: M - 1; y = sin(x ./ (100 * pi)); end此時(shí)我們?cè)儆胻imit在M=20000時(shí)進(jìn)行時(shí)間測(cè)量,如圖5:
由圖可知我們使用向量化時(shí),在M=20000時(shí)要比預(yù)分配數(shù)組快3倍。接下來測(cè)量M的數(shù)量級(jí)為200000和2000000的時(shí)間。如圖6所示:
由此可見,不帶循環(huán)sinfun3的執(zhí)行速度和帶一個(gè)循環(huán)的sinfun2的執(zhí)行速度大致相同,但又略快于sinfun2。
在教材中為了為了更好地說明這個(gè)比較兩種優(yōu)化方法,給出了下面這個(gè)例子。
這個(gè)例子是基于公式f(x) = Asin(u0x + v0y)創(chuàng)建一幅合成圖像,首先使用嵌套的for循環(huán)來計(jì)算f:
function f = twodsin1(A, u0, v0, M, N) %f = zeros(M, N); for c = 1 : Nv0y = v0 * (c - 1);for r = 1 : Mu0x = u0 * (r - 1);f(r, c) = A * sin(u0x + v0y);end end不使用預(yù)分配和使用后的執(zhí)行時(shí)間如圖7所示:
我們?cè)谶@里發(fā)現(xiàn)使用預(yù)分配前后,執(zhí)行時(shí)間的差距并沒有很大。接下來來看向量化后的結(jié)果。
在實(shí)驗(yàn)中使用一個(gè)meshgrid的MATLAB函數(shù)將函數(shù)重寫為沒有for循環(huán)的形式。
function f = twodsin2(A, u0, v0, M, N) r = 0 : M - 1; c = 0 : N - 1; [C, R] = meshgrid(c, r); f = A * sin(u0 * R + v0 * C);繼續(xù)用timeit測(cè)試,得到的結(jié)果如圖8:
可見使用向量化后,比使用預(yù)分配快了30%,比不使用任何優(yōu)化方法快了50%。
小結(jié)
綜合以上兩個(gè)實(shí)驗(yàn)表明,兩種代碼優(yōu)化方法(預(yù)分配數(shù)組和向量化循環(huán))在具體的使用中的差別并不是很大,都可以提升循環(huán)運(yùn)行的速度。我們可以在遇到具體問題后,根據(jù)具體情況選擇具體的方法:若是循環(huán)存在沒有預(yù)分配內(nèi)存的問題,那我們可以考慮采用預(yù)分配的方法,這樣對(duì)代碼的改動(dòng)不大,更直觀,也更容易表示我們代碼得到實(shí)際工作機(jī)理;若是確定沒有預(yù)分配的問題,就可以選擇向量化循環(huán)的辦法,這樣與基于循環(huán)的代碼相比,向量化后的代碼更易于閱讀,更為簡(jiǎn)潔。
總結(jié)
以上是生活随笔為你收集整理的MATLAB中代码优化的两种方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博易大师 行情服务器文件,博易大师目录
- 下一篇: 数字图像处理——第三章 空间域图像增强(