Octave 程式設計教程/迴圈和條件
迴圈用於重複執行一段程式碼,具體次數根據迴圈型別而定,可能是已知的,也可能是未知的。使用迴圈,你可以繪製一些漂亮的圖案,例如分形和隨機點繪製的形狀。
我們使用 for 迴圈來重複執行一段程式碼,針對已知值列表。例如,我們將計算一個值列表的平均值。平均值由下式計算得出
我們設定一個包含一些值的向量
octave:1> x = [1.2, 6.3, 7.8, 3.6];
並使用以下程式碼計算平均值
octave:2> sum = 0; octave:3> for entry = x, octave:4> sum = sum + entry; octave:5> end; octave:6> x_mean = sum / length(x)
第 2 行:將 sum 設定為 0。
第 3 行:對於 x 中的每個值,將其分配給 entry。
第 4 行:將 sum 增加 entry。
第 5 行:當 x 中沒有更多成員時,結束 for 迴圈。
第 6 行:將 sum 的最終值除以 x 的長度,並將結果分配給 x_mean。
待辦:提供一個更好的示例並解釋程式碼。
一般來說,我們編寫 for 迴圈的格式如下
for variable = vector ... end
... 代表程式碼塊,該程式碼塊對於 vector 中的每個值都會執行一次。
謝爾賓斯基三角形是一種分形,可以透過一個非常簡單的演算法生成。
- 從等邊三角形的頂點開始。
- 隨機選擇三角形的一個頂點。
- 移動到當前位置與所選頂點之間中點的點。
- 從步驟 2 開始重複。
透過遵循此過程繪製你訪問的點,可以生成以下影像。

生成該分形的程式碼如下所示。請注意,此程式碼使用一個非常簡單的 for 迴圈來生成分形(for i = 1:N ; ... ; end)
axis ([-1, 1, -0.75, 1.25], "square");
figure(1, "visible", "off"); % no plotting window
hold on;
% defining the vertices of an equilateral triangle (symmetric to y-axis)
V = [ 0, 1; % top vertex
cos( (pi/2)+(2*pi/3) ), sin( (pi/2)+(2*pi/3) ); % left vertex
cos( (pi/2)-(2*pi/3) ), sin( (pi/2)-(2*pi/3) ) % right vertex
];
r = floor(3*rand(1)+0.9999999999); % integer random number in [1:3]
x = [ V(r,1), V(r,2) ]; % initializing x on random vertex
for i = 1:1000 % !!! 100000 => time=130m57.343s
r = floor(3*rand(1)+0.9999999999); % integer random number in [1:3]
x = ( x+V(r,[1:2]) )./2; % halfway, current to random vertex
plot(x(1),x(2), ".");
endfor
print -dpng "sierpinski_m.png";
出於效能原因,最好在 'for' 迴圈中執行儘可能少的任務,並且應儘可能將 plot 這樣的圖形操作移到迴圈之外。透過簡單地將所有 x 值儲存在矩陣中,然後像下面這樣繪製,程式碼生成此圖的執行時間會縮短到幾秒,即使迭代超過 100,000 個元素(上面的程式碼警告不要這樣做)。
axis ([-1, 1, -0.75, 1.25], "square");
figure(1, "visible", "off"); % no plotting window
hold on;
% defining the vertices of an equilateral triangle (symmetric to y-axis)
V = [ 0, 1; % top vertex
cos( (pi/2)+(2*pi/3) ), sin( (pi/2)+(2*pi/3) ); % left vertex
cos( (pi/2)-(2*pi/3) ), sin( (pi/2)-(2*pi/3) ) % right vertex
];
r = floor(3*rand(1)+0.9999999999); % integer random number in [1:3]
x(1,:) = [ V(r,1), V(r,2) ]; % initializing x as a matrix this time.
for i = 2:100000 % Safe now: 100000 => time=7.85346s
r = floor(3*rand(1)+0.9999999999); % integer random number in [1:3]
x(i,:) = ( x(i-1,:)+V(r,[1:2]) )./2; % Add each newly calculated x value to the matrix
endfor
plot(x(:,1),x(:,2), "."); % plot the entire matrix just once
print -dpng "sierpinski_m.png";
透過提前將 x 初始化為完整最終大小的矩陣,可以在現代硬體上將處理時間進一步縮短到 1 或 2 秒。一般來說,如果迴圈可以用向量化替換,那麼就應該這樣做。
- 編寫一個指令碼,對前 N 個整數求和。你可以使用公式 檢查你的結果。
- 編寫一個指令碼,執行與
linspace函式相同的功能。它應該從某個值xstart開始,在xstop處結束,並建立一個向量,其中包含 N 個從xstart到xstop均勻分佈的值。你可以使用zeros函式來建立一個填充了零的正確大小的向量。使用help zeros瞭解該函式的工作原理。
while 迴圈也會重複執行一段程式碼多次,但停止執行取決於一個邏輯條件。例如
x = 1.0; while x < 1000 disp(x); x = x*2; endwhile
將 x 乘以 2,直到其值超過 1000。這裡,x < 1000 是迴圈的條件。只要條件成立(為真),迴圈就會繼續執行。一旦條件不成立,迴圈就會終止,並執行迴圈後的第一條指令。
while 迴圈的一般形式如下
while condition ... endwhile
- 編寫一個指令碼,計算最小的正整數 n,使得 對於某些實數 a 和 b。(也就是說,找到 a 的最小冪,該冪至少為 b。)使用
log函式被認為作弊。
曼德勃羅特集合是另一個分形,它是透過檢查複數變大的速度來生成的。對於每個複數 c,
- 從 開始。
- 令
- 找到第一個 i,使得 .
我們將記錄所有這些i值,併為每個值分配一種顏色。這用於生成類似於此的影像。

您可以從Mandelbrot.m下載生成此分形的程式碼。請注意,有一個 while 迴圈(在一些 for 迴圈內),用於測試複數z的模量是否小於2
while (count < maxcount) & (abs(z) < 2) ... endwhile
while 迴圈中的第一個條件檢查我們是否沒有執行太多迭代。對於一些c值,如果我們讓它繼續,迭代將永遠持續下去。
另請參閱Christopher Wellons的另一個版本
do...until語句
[edit | edit source]這些迴圈與 while 迴圈非常相似,因為它們根據給定條件為真還是假來繼續執行。但是,while 和 do...until 迴圈之間有一些重要的區別。
while迴圈的條件位於迴圈的開頭;do...until迴圈的條件位於迴圈的結尾。while迴圈只要條件為真就重複;do...until迴圈只要條件為假就繼續。while將執行 0 次或更多次(因為條件位於開頭);do...until迴圈將執行 1 次或更多次(因為條件位於結尾)。
do...until 迴圈的一般形式是
do ... until condition
練習
[edit | edit source]編寫一個指令碼,計算兩個正整數的最大公約數(GCD)。您可以使用歐幾里得演算法來實現。
挑戰
[edit | edit source]編寫一個指令碼,生成均勻分佈的隨機數對(a,b)
- 在圓盤(下面的第一個影像);
- 如下面的第二個影像所示
break 和 continue 語句
[edit | edit source]有時需要在迴圈執行的中間某個位置停止迴圈,或者繼續到 for 迴圈中的下一個值,而無需為當前值執行迴圈程式碼的其餘部分。這就是 break 和 continue 語句有用的地方。
以下程式碼演示了 break 語句的工作原理。
total = 0;
while true
x = input('Value to add (enter 0 to stop): ');
if x == 0
break;
endif
total = total+x;
disp(['Total: ', num2str(total)]);
endwhile
如果沒有 break 語句,迴圈將永遠繼續執行,因為 while 迴圈的條件始終為真。break 允許您跳過迴圈的末尾(到 endwhile 之後的語句)。
break 語句可以用於任何迴圈:for、while 或 do...until。
continue 語句也從迴圈內部跳轉,但返回到迴圈的開頭,而不是到迴圈的末尾。在一個
for迴圈中,向量中的下一個值將被分配給 for 變數(如果有的話),並使用該值重新啟動迴圈;while迴圈中,將重新測試迴圈開頭的條件,如果條件仍然為真,則繼續迴圈;do...until迴圈中,將測試迴圈末尾的條件,如果條件仍然為假,則從開頭繼續迴圈。
例如,以下程式碼將用 1 填充方陣的下三角部分,其餘部分用 0 填充。
N = 5;
A = zeros(N); % Create an N x N matrix filled with 0s
for row = 1:N
for column = 1:N
if column > row
continue;
endif
A(row, column) = 1;
endfor
endfor
disp(A);
請注意,內部 for 跳過(繼續)為 A 的條目分配 1 的程式碼,只要列索引大於行索引。
if 語句
[edit | edit source]if 語句的一般形式是
if condition1 ... elseif condition2 ... else ... endif
如果 condition1 評估為真,則執行緊隨 if 之後的塊中的語句。如果 condition1 為假,則檢查下一個條件(elseif 中的 condition2),如果為真則執行其語句。您可以擁有任意數量的 elseif 語句。如果所有條件都評估為假,則執行 else 之後的最後一組語句。請注意,if 語句的 elseif 和 else 部分是可選的。
以下都是有效的 if 語句
% Take the log of the absolute value of x
if x > 0
y = log(x);
elseif x < 0
y = log(-x);
else
disp("Cannot take the log of zero.");
endif
x = input("Enter a value: ");
if x > 0
disp("The number is positive");
endif
if x < 0
disp("The number is negative");
endif
if x == 0
disp("The number is zero");
endif
示例:分形蕨
[edit | edit source]此演算法還不完整。請檢視可從http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=4372&objectType=file獲得的 .m 檔案。
右側的影像可以使用以下演算法生成
1. Let x1 and y1 be random values between 0 and 1.
2. Choose one of the linear transformations below to calculate (xi+1, yi+1) from (xi, yi):
1. xi+1 = 0
yi+1 = 0.16yi
2. xi+1 = 0.20xi − 0.26yi
yi+1 = 0.23xi + 0.22yi + 1.6
3. xi+1 = −0.15xi + 0.28yi
yi+1 = 0.26xi + 0.24yi + 0.44
4. xi+1 = 0.85xi + 0.04yi
yi+1 = −0.04xi + 0.85yi + 1.6
The first transformation is chosen if probability 0.01, the second and third with probability 0.07 each and the fourth with probability 0.85.
3. Calculate these values for i up to at least 10,000.
您可以下載生成此分形的程式碼為 fracfern.m(目前已停用)。