• 沒有找到結果。

Chapter 5 迴圈與向量優化

N/A
N/A
Protected

Academic year: 2022

Share "Chapter 5 迴圈與向量優化"

Copied!
56
0
0

加載中.... (立即查看全文)

全文

(1)

Chapter 5 迴圈與向量優化

Hung-Yuan Fan (范洪源)

Department of Mathematics, National Taiwan Normal University, Taiwan

Spring 2017

(2)

Outline

5.1 while 迴圈 5.2 for 迴圈

5.3 邏輯陣列與向量優化 5.6 textread 函式

(3)

Section 5.1

while 迴圈

(4)

Introduction

迴圈(loops)是㇐種 MATLAB 架構,允許我們重複執行㇐

連串的宣告式。

兩個基本的迴圈架構為:while 迴圈(while loops)以及 for 迴圈(for loops)。

wile 迴圈: 只要滿足某些條件,將重複執行特定的程式區 塊,直到這些條件不滿足後,才結束迴圈,故其執行次數並 非固定。

for 迴圈: 以㇐個確定的次數重複執行特定的程式區塊。

向量化或是向量優化(vectorization)是 MATALB 另㇐

種更快速的方式,用來執行如同許多 for 迴圈㇐樣的功能。

(5)
(6)

while 迴圈的範例

% 本範例計算 1 + 2 + 3 + 4 + 5 的總和。

i = 1; x = 0;

while

i < 6 x = x + i;

i = i + 1;

end

fprintf(' 正整數 1 加到 5 的總和為 %d

\n',x);

(7)

whike 範例的流程圖

(8)

while 迴圈的範例 total = 0; num = 2;

while

num <= 100

if

isprime(num)

total = total + num;

end

num = num + 1;

end

fprintf('1 到 100 之間的質數總和為 %d

\n',total);

(9)

範例 5.1: 統計分析 (1/5)

1. 宣告問題

計算㇐組資料的平均數及標準差,假設所有的測量值均為正 數或零,並且使用㇐個負值作為資料輸入的結尾。

2. 定義輸入和輸出

輸入: ㇐組不知道總個數的正數或零值。

輸出: 列出輸入資料的平均數、標準差和資料點的總個數。

3. 設計演算法

這個程式將會分成 3 個主要的步驟來執行:

1 收集輸入資料

2 計算平均數及標準差

¯

x =

1

N

N

i=1

x i , s =

N

N

i=1

x 2 i

(

N i=1

x i

)

2

N(N − 1)

(10)

範例 5.1: 統計分析 (2/5)

4. 將演算法變成 MATLAB 宣告式 虛擬碼 (pseudocode):

將 n, sum_x 及 sum_x2 初始化為 0。

提示使用者輸入並讀取需要的第㇐個 x 值。

while

x >= 0 n

← n+1;

sum_x

← sum_x + x;

sum_x2

← sum_x2 + x^2;

提示使用者輸入並讀取下㇐個 x 值。

end

計算資料點的平均數 x_bar 與標準差 s。

(11)

範例 5.1: 統計分析 (3/5)

MATLAB 程式碼: (檔名為 stats_1.m) n = 0; sum_x = 0; sum_x2 = 0;

x = input('Enter first value: ');

while

x >= 0 n = n + 1;

sum_x = sum_x + x;

sum_x2 = sum_x2 + x^2;

x = input('Enter next value: ');

end

x_bar = sum_x / n;

s = sqrt( (n*sum_x2-sum_x^2) / (n*(n-1));

fprintf('The mean of data is: %f

\n',x_bar);

fprintf('The standard deviation is: %f

\n',s);

fprintf('The number of data is: %f

\n',n);

(12)

範例 5.1: 統計分析 (4/5)

5. 測試程式

>> stats_1

Enter first value: 3 Enter next value: 4 Enter next value: 5 Enter next value: -1

The mean of data is: 4.000000

The standard deviation is: 1.000000 The number of data is: 3.000000

>> stats_1

Enter first value: -1

(13)

範例 5.1: 統計分析 (5/5)

正確的 MATLAB 程式碼: (檔名為 stats_2.m) n = 0; sum_x = 0; sum_x2 = 0;

x = input('Enter first value: ');

while

x >= 0 n = n + 1;

sum_x = sum_x + x; sum_x2 = sum_x2 + x^2;

x = input('Enter next value: ');

end if

n < 2

disp('At least 2 values must be entered!');

else

x_bar = sum_x / n;

s = sqrt( (n*sum_x2-sum_x^2) / (n*(n-1));

fprintf('The mean of data is: %f

\n',x_bar);

\n',s);

(14)

Section 5.2

for 迴圈

(15)

for 迴圈(for loops)是㇐種可執行程式區塊特定次數的迴 圈。

形式如下:

(16)

for 迴圈的範例 total = 0;

for

num = 2:100 % num = 2,3,4,…,100

if

isprime(num)

total = total + num;

end end

fprintf('1 到 100 之間的質數總和為 %d

\n',total);

(17)

計算向量元素的總和 (檔名: vec_sum.m)

total = 0;

for

num = [-5.6 -1 4 7.2] % num = -5.6 ,-1, 4, 7.2 total = total + num;

end

fprintf(' 向量元素的總和為 %f

\n',total);

>> vec_sum

向量元素的總和為4.600000

>> sum([-5.6, -1, 4, 7.2]) ans =

4.6000

(18)

迴圈變數被指派為陣列 (檔名: for_arr.m) for

ii = [1 2;3 4] % 矩陣

[1 2 3 4 ]

被指派給變數 ii ii

end

>> for_arr ii =

1 3 ii =

2

(19)

計算 p-級數的和 (檔名: p_series.m)

p = 2.7; data = [];

for

k = 0:8 N = 10^k;

n = 1:N;

S_N = sum(1./(n.^p));

data = [data;N S_N];

end

semilogx(data(:,1),data(:,2),'bo-');

title('Partial sums of a p-series with p = 2.7');

xlabel('N');

ylabel('partial sum S_N');

(20)

程式執行結果 (承上例)

下列圖形顯示 ∑

n=1

n

1

p

的收斂與發散,其中 p = 2.7 和 p = 0.7:

(21)

使用 for 迴圈的重要細節 (1/2)

1. 縮排迴圈的程式本體

向後縮排2 個以上的空格,以增加程式碼的可讀性。

在編輯/偵錯視窗 (Editor) 中,善用 “反白 MATLAB 宣告式

→ 按下滑鼠右鍵 → 選取 Smart Indent”。

2. 不能在迴圈的程式本體中修改到迴圈指標

因為指標變數在迴圈裡通常被當成計數的工具使用,而修改 迴圈指標可能會導致錯誤,或是產生難以找到的錯誤。

for

ii = 1:10

· · ·

ii = 5; % Error!

· · ·

a(ii) = <calculation>

· · ·

(22)

使用 for 迴圈的重要細節 (2/2)

3. 預先配置 (preallocate) 陣列記憶體空間

如果陣列在迴圈開始執行之前,就預先配置其所需的最大空 間,當程式執行時,就不需要經過複製的過程。

這將大幅地增加執行迴圈的速度。例如:

square = zeros(1,100);

for

ii = 1:100 square(ii) = ii^2;

end

4. 向量優化陣列

使用向量化的宣告來取代迴圈的過程,被稱為向量優化 (vectorization)。向量優化可以大幅地改善許多 MATLAB 程 式的執行效率。

(23)

MATLAB 動態編譯器

在 6.5 的版本以後,增加動態 (Just-in-Time, JIT) 編譯器 的工具。

在執行程式碼之前先編譯 (compile) 它,而非直譯程式碼。

可以提升 for 迴圈的執行速度,幾乎可與向量優化㇐樣快。

動態編譯器有許多限制,而且這些限制因所使用的 MATLAB 版本而有所差異。

向量優化的方式通常能比動態編譯器更有效率。

(24)

範例 5.5: 比較迴圈與向量優化

請比較下列寫法所需的計算時間:

1 不事先初始化陣列,利用 for 迴圈計算 1 至 10000 每個整 數的平方。

2 先用 zeros 函式去預先配置㇐個陣列,再利用 for 迴圈計 算 1 至 10000 每個整數的平方 (這將啟動動態編譯器)。

3 利用向量計算 1 至 10000 每個整數的平方。

(25)

MATLAB 程式碼 (1/3)

% 檔名: timings.m

% 第㇐種寫法 maxcount = 1000;

tic;

for

jj = 1:maxcount clear square

for

ii = 1:10000

square(ii) = ii^2;

end end

average1 = (toc)/maxcount;

(26)

MATLAB 程式碼 (2/3)

% 第二種寫法 tic;

for

jj = 1:maxcount clear square

square = zeros(1,10000);

for

ii = 1:10000 square(ii) = ii^2;

end end

average2 = (toc)/maxcount;

(27)

MATLAB 程式碼 (3/3)

% 第三種寫法 tic;

for

jj = 1:maxcount clear square ii = 1:10000;

square = ii.^2;

end

average3 = (toc)/maxcount;

% 顯示三種寫法的計算時間

fprintf(’Loop / uninitialized array = %8.5f

\n’, average1);

fprintf(’Loop / initialized array / JIT = %8.5f

\n’, average2);

fprintf(’Vectorized = %8.5f

\n’, average3);

(28)

輸出結果 (承上頁)

>> timings

Loop / uninitialized array = 0.00261 Loop / initialized array / JIT = 0.00010 Vectorized = 0.00002

備註: 上述結果的運算環境為

機器型號: ASIS Nootebook (G501JW)

微處理器: Intel Core i7-4720HQ CPU@2.60GHz 2.59GHz

記憶體數: 12 GB

作業系統: Windows 8.1

(29)

使用 break 與 continue 指令

(30)

指令 break 的範例 (檔名: test_break.m)

for

ii = 1:5

if

ii == 3 break;

end

fprintf('ii = %d

\n', ii);

end

disp(['End of loop!']);

>> test_break ii = 1

ii = 2

(31)

指令 continue 的範例 (檔名: test_continue.m)

for

ii = 1:5

if

ii == 3 continue;

end

fprintf('ii = %d

\n', ii);

end

disp(['End of loop!']);

>> test_continue ii = 1

ii = 2 ii = 4 ii = 5

End of loop!

(32)

巢狀迴圈 (1/2)

使用巢狀迴圈的注意事項

如果㇐個迴圈內有另外㇐個迴圈,這兩個迴圈稱為巢狀迴圈 (nested loops)。

如果 for 迴圈為巢狀結構,它們應該擁有獨立的指標變數。

如果 break 或 continue 指令在巢狀迴圈內出現,則這些 宣告與包含它們的最內層迴圈有關聯。

如果可能的話,請使用向量優化的宣告式取代巢狀迴圈結 構。

在使用巢狀迴圈之前,請預先分配記憶體給迴圈內所運行的

(33)

break 和巢狀迴圈結合的範例 (檔名: nested_for.m)

for

ii = 1:3

for

jj = 1:3

if

jj == 3

break;

end

product = ii * jj;

fprintf('%d * %d = %d

\n',ii,jj,product);

end

% for jj

fprintf('End of inner loop

\n');

end

% for ii

fprintf('End of outer loop

\n');

(34)

輸出結果 (承上例)

>> nested_for 1 * 1 = 1 1 * 2 = 2

End of inner loop 2 * 1 = 2

2 * 2 = 4

End of inner loop 3 * 1 = 3

3 * 2 = 6

End of inner loop

(35)

Section 5.3

邏輯陣列與向量優化

(36)

邏輯陣列的特性

由邏輯值 true(1) 或 false(0) 所形成的陣列稱為邏輯陣列 (logical array)。

邏輯陣列可以當做算術運算的遮罩(mask)陣列。

遮罩陣列是㇐個可以用來選擇某些陣列的元素,做為算術運 算的元素。指定的運算會作用在選擇的元素上,而不會作用 在其餘未被選擇的元素上。

這是㇐個非常快速而聰明的方式來執行陣列子集的運算,因 其不需使用任何的迴圈或分支結構。

(37)

遮罩陣列的範例

a = [1 2 3; 4 5 6; 7 8 9]; c = a;

>> a >> b = a > 5 % 邏輯陣列

a = b =

1 2 3 4 5 6 7 8 9

0 0 0 0 0 1 1 1 1

>> a(b) = sqrt(a(b)) >>

c( ∼b) = c(∼b).^2

a = c =

1.0000 2.0000 3.0000 4.0000 5.0000 2.4495 2.6458 2.8284 3.0000

1 4 9

16 25

6 7 8 9

(38)

使用邏輯陣列產生等效的 if/else 架構 (1/2)

MATLAB 的原始程式碼

a = [1 2 3; 4 5 6; 7 8 9];

for

ii = 1:size(a,1)

for

jj = 1:size(a,2)

if a(ii,jj) > 5

a(ii,jj) = sqrt(a(ii,jj));

else

a(ii,jj) = a(ii,jj)^2;

end % if

end

% jj

(39)

使用邏輯陣列產生等效的 if/else 架構 (2/2)

邏輯陣列可產生等效的分支敘述

a = [1 2 3; 4 5 6; 7 8 9];

b = a > 5;

a(b) = sqrt(a(b)); % 取大於 5 的元素開平方根

a( ∼b) = a(∼b).^2;

% 取小於或等於 5 的元素計算平方

>> a a =

1.0000 4.0000 9.0000

16.0000 25.0000

2.4495 2.6458 2.8284 3.0000

(40)

邏輯陣列應用於基本列運算上

試用基本列運算 (elementary row operation) 與邏輯陣列 (或是遮 罩陣列),將矩陣

A =



1 0 1 0

2

2 2 2

3

3 3 3

4

4 4 4



的第㇐行元素

a 21 = 2, a 31 = 3, a 41 = 4

全部消為零。

(41)

MATLAB 程式碼 (1/2)

>> A = [1 0 1 0; 2 2 2 2; 3 3 3 3; 4 4 4 4];

>> jj = logical(A(1,:));

% 非零元素設為 true(1),零元素設為 false(0)

>> A(2,jj) = (-2) * A(1,jj) + A(2,jj) A =

1 0 1 0 0 2 0 2 3 3 3 3 4 4 4 4

(42)

MATLAB 程式碼 (2/2)

>> A(3,jj) = (-3) * A(1,jj) + A(3,jj) A =

1 0 1 0 0 2 0 2 0 3 0 3 4 4 4 4

>> A(4,jj) = (-4) * A(1,jj) + A(4,jj) A =

1 0 1 0 0 2 0 2

(43)

Section 5.6

textread 函式

(44)

讀取混合資料型態的檔案

(45)

函式 textread 的使用範例 (1/2)

>> type test_input.dat

James Jones O+ 3.51 23 Yes Sally Smith A+ 3.28 22 No

>> [first,last,blood,gpa,age,answer] = ...

textread('test_input.dat','%s %s %s %f %d %s');

>> whos

Name Size Bytes Class age 2

× 1 16

double answer 2

× 1 234

cell blood 2

× 1 232

cell first 2

× 1 244

cell gpa 2

× 1 16

double

× 1 244

(46)

函式 textread 的使用範例 (2/2)

>> clear

all

% 函式 textread 允許忽略某些資料欄位不被讀取,例如:

>> [first,last,gpa] = textread('test_input.dat',...

'%s %s %*s %f %*d %*s');

>> whos

Name Size Bytes Class first 2

× 1 244

cell gpa 2

× 1 16

double last 2

× 1 244

cell

(47)

MATLAB 支援四種常用的資料檔案格式,如下表所示:

(48)

以逗點隔開的資料檔案

以逗號隔開的資料稱為 CSV(comma separated value)。

函式 csvread 與 csvwrite 可用來存取 CSV 型態的資料。

(49)

CSV 檔案的寫入與讀取

>> A = magic(3) %A 是㇐個 3

× 3 魔術方陣

A =

8 1 6 3 5 7 4 9 2

>> csvwrite('magic3.csv',A); % 以逗點為分隔符號

>> type

magic3.csv

8,1,6

3,5,7 4,9,2

>> B = csvread('magic3.csv') B =

8 1 6

(50)

以特定符號隔開的數據處理

函式 dlmread 與 dlmwrite 可存取不是以逗號分隔的數據 資料。

dlm 是 delimiter 的縮寫,分隔符號之意。

(51)

DLM 檔案的寫入與讀取

>> A = magic(3); %A 是㇐個 3

× 3 魔術方陣

>> dlmwrite('magic3.dlm',A,'

\t'

); % 以空白為分隔符號

>> type

magic3.dlm

8 1 6

3 5 7

4 9 2

>> B = dlmread('magic3.dlm','

\t'

) B =

8 1 6 3 5 7 4 9 2

(52)

開啟和關閉文字檔

(53)

寫入和讀取文字檔

(54)

計算 p-級數的部分和 (檔名: test_pseries.m)

clc,clear

all;

fid = fopen('results.txt','w');

fprintf(' N S_N

\n');

fprintf(fid,' N S_N

\n');

p = 2.7;

for

k = 0:8 N = 10^k;

n = 1:N;

S_N = sum(1./(n.^p));

fprintf('10^%d %12.6f

\n',k,S_N);

fprintf(fid,'10^%d %12.6f

\n',k,S_N);

(55)

檢視計算結果 (承上頁)

>> test_pseries

除了螢幕上會顯示 N 與 p-級數部分和 S

N

=

N n=1

n

1

p

的計算結 果之外,這些數據資料同時也會寫入 ASCII 格式的文字檔 案

results.txt

中。

>> type

results.txt

N S_N

10^0 1.000000 10^1 1.263481 10^2 1.274032 10^3 1.274260 10^4 1.274265 10^5 1.274265 10^6 1.274265

(56)

Thank you for your attention!

參考文獻

相關文件

「先按住 CTRL

Table 進入 Edit Mode 利用右鍵+S 控制大小 利用右鍵+R 控制旋轉度 利用右鍵+G 控制軌道位子 利用右鍵+E 新增軌道.. 步驟 十一

AR &amp; VR Professional Development Training 19 HKU e-Learning Development Laboratory.. 接著開始編輯目標影像,按下右方的Click to Upload Overlay Or Click to

Department of Mathematics, National Taiwan Normal University, Taiwan..

Department of Mathematics, National Taiwan Normal University, Taiwan..

… 點選 LinkButton 控制 項的 (DataBindings) 屬性,在自訂繫結

afx_msg void OnLButtonDown(UINT nFlags, CPoint point). {……;

然後,他在同樣的器皿中放入另外一隻大白 鼠,在它掙扎了 5分鐘左右的時候,放入一