流程控制 : if, for, while, repeat Textbook reading: Chapter 7. 條件執行 :if 指令或 if-else 指令. 當條件 A 為 TRUE 時, 執行命令 C 的語法為 if ( A ) C 當條件 A 為 TRUE 時執行命令 C, 否則執行命令 D 的語法為 if ( A ) C else D A simple example. x <- 0.5 y <- 0 if ( x > 3 ) y <- 2 y ## (x>3) is FALSE, so y is 0 if ( x > 3 ) y <- 2 else y <- 10 y ## (x>3) is FALSE, so y is 10 Example 1. Write an R function called add that asks the user to enter from screen two numbers and enter the sum of the two numbers. If the user enters the correct sum, print Your answer is correct. Good job!. If the user fails to enter the right sum, print the correct answer on the screen. add <- function() x <- readline("please enter a number: \n") y <- readline("please enter another number: \n") question <- paste("please enter the sum of ", x," and ", y, ": \n", sep="") z <- readline(question) x <- as.numeric(x) y <- as.numeric(y) z <- as.numeric(z) if (z==(x+y)) cat("your answer is correct. Good job!\n") else cat( paste("the sum of ", x, " and ", y," should be ",x+y, "!\n", sep="") ) add() #test the function Be sure that "else" appears at the same line where the "if" part ends ( 使用 else 時, else 必須和 if 部分結尾的 在同一行 ). Run the two sets of commands below to see which one yields an error message. 1
######## First set of commands x <- 0.5; y <- 0 if (x>3) y <- 1 else y <- 2 ######## Second set of commands x <- 0.5; y <- 0 if (x>3) y <- 1 else ### 注意 : else 移到了 if 部分的最後一行, 這樣才行 y <- 2 Example 2. 寫一個函數 abs0.fun 計算絕對值. ### define abs0.fun abs0.fun <- function(x) if (x>0) return(x) else return(-x) ### compute -1 and 1 abs0.fun(-1); abs0.fun(1) 在函數運算時, 一旦執行了 return 指令, 所有運算就結束了. 因此 Example 2 的函數 abs0.fun 也可改寫如下 abs1.fun <- function(x) if (x>0) return(x) return(-x) abs1.fun(-1); abs1.fun(1) Example 3. Suppose that 0 if x < 0; f(x) = x if 0 x 1; 1 if x > 1. Define a function f in R that returns f(x) for a input value x. Solution. 2
f <- function(x) if ( x<0) return(0) if ( (0 <= x)&(x <= 1) ) return(x) return(1) f(-1); f(0.5); f(3) 固定次數迴圈 : for 指令. 假設有 k 個指令 C(1),..., C(k) 要依序完成. 語法為 for ( i in 1:k) C(i) 通常在 for 迴圈開始前, 會定義一個存結果的物件, 而在迴圈執行時更新物件. Example 4. Suppose that a sequence a i i=1 is defined by a 1 = 2 and a i+1 = a i for i 1. (a) Write down R commands that compute a 10. (b) Write down R commands that compute the vector (a 1,..., a 10 ). Solutions. #(a) a <- 2 for (i in 1:9) a <- sqrt(a) a #(b) a <- rep(2, 10) for (i in 1:9) a[i+1] <- sqrt(a[i]) a Example 5. 當 x 為數值向量時, Example 2 的函數 abs0.fun 無法計算 abs0.fun(x). 寫一個函數 abs.fun 計算絕對值, 而且函數 input 可為一 numeric vector. abs.fun <- function(x) ans <- x #define a vector to store the results n <- length(x) for (i in 1:n) ans[i] <- abs0.fun(x[i]) return(ans) 可用 abs.fun(c(-1,1,-2)) 測試計算結果. 3
R 中使用迴圈比較慢. 所以如果能避免使用迴圈就避免. 例如以下函數 abs2.fun 未使用迴圈也可計算絕對值, 而且函數 input 可為一 numeric vector. abs2.fun <- function(x) ans <- x ans2 <- -x ans[x<0] <- ans2[x<0] return(ans) 測試計算時間 x <- 1:5000000 t1 <- proc.time() y1 <- abs2.fun(x) t1 <- proc.time() - t1 t2 <- proc.time() y2 <- abs.fun(x) t2 <- proc.time() - t2 t1 t2 在 R 中內建計算絕對值的函數叫做 abs, 其函數 input 可為一 numeric vector. 矩陣相關指令用法 X <- matrix(0, 4,3) #define X as a zero matrix with 4 rows and 3 colunms dim(x)[1] #number of rows of X dim(x)[2] #number of columns of X X[,2] #X 的第 2 個 column 形成的向量 X[2,] #X 的第 2 個 row 形成的向量 X[2, c(1,3)] #X 的第 2 個 row 的第 1,3 個元素形成的向量 Example 6. 寫一個函數 m.prod 計算矩陣相乘. m.prod <- function(a, B) m <- dim(a)[1] n <- dim(b)[2] if (dim(b)[1]!=dim(a)[2]) return("error!") D <- matrix(0, m, n) ## 定義一個 m x n 的零矩陣 for (i in 1:m) for (j in 1:n) D[i,j] <- sum(a[i,]*b[,j]) return(d) 4
測試 A <- matrix(1:6, 3,2) B <- t(a) A %*% B m.prod(a, B) 畫 z = f(x, y) 的函數圖形, 其中 (x, y) x 1,..., x m y 1,..., y n. R 指令 : persp(xlist, ylist, z) xlist 為向量 (x 1,..., x m ) ylist 為向量 (y 1,..., y n ) z 為 m n 矩陣, z 的第 (i, j) 位置為 f(x i, y j ). Example 7. Plot z = x 2 + y 2 for (x, y) 0.9, 0.8,... 0.9 2.20, 2.19,..., 2.20 using R command persp. x <- seq(-0.9, 0.9, by=0.1) y <- seq(-2.20, 2.20, by=0.01) m <- length(x) n <- length(y) z <- matrix(0, m, n) for (i in 1:m) for (j in 1:n) z[i,j] <- x[i]^2+y[j]^2 persp(x,y,z) #You can adjust the viewing angle by changing the parameters theta and phi in persp. persp(x,y,z, theta=30, phi=15) persp(x,y,z, theta=0, phi=15) persp(x,y,z, theta=0, phi=30) 使用迴圈定義具有規律型態的矩陣 Example 8. Write down R commands that define a 100 100 matrix M, where M is 1 2 3... 100 0 1 2... 99 0 0 1... 98. 0 0 0... 1 Solution. 5
n <- 100 M <- matrix(0, n, n) for (i in 1:n) M[i,i:n] <- 1:(n-i+1) M 當迴圈次數不固定, 而是在條件下停止執行時, 可使用 while 或 repeat. 假設當條件 A 為 TRUE 時要執行工作 B, 而在條件 A 為 FALSE 時停止執行. while 語法為 while(a) B 假設要重複執行工作 B, 直到條件 A 為 TRUE 時停止執行. repeat 語法為 repeat B if (A) break Example 9. 重複執行 Example 1 中的 add 函數, 每次詢問使用者是否繼續, 直到使用者輸入 N 時停止執行. 先定義 add 函數和詢問字串 S. add <- function() x <- readline("please enter a number: \n") y <- readline("please enter another number: \n") question <- paste("please enter the sum of ", x," and ", y, ": \n", sep="") z <- readline(question) x <- as.numeric(x) y <- as.numeric(y) z <- as.numeric(z) if (z==(x+y)) cat("your answer is correct. Good job!\n") else cat( paste("the sum of ", x, " and ", y," should be ",x+y, "!\n", sep="") ) S <- "Do you want to play this game again? \n" S <- paste(s, "Enter N to stop or something else to play again: \n", sep="") 用 repeat 加上 break 寫法如下 : repeat add() conti <- readline(prompt=s) if (conti=="n") break 6
用 while 寫法如下 : conti <- "Y" while( conti!="n" ) add() conti <- readline(prompt=s) Example 10. 以牛頓法計算 x 2 2 = 0 的正根. 取起始解為 1. 當本次疊代的解和前一次疊代的解相差 < 0.001 時停止疊代. 上述問題可改寫如下. 令 x n 為第 n 次的疊代解, 則 x 1 = 1 且 令 m 為一正整數使得 x n+1 = x n x2 n 2 2x n for n 1. x m+1 x m < 0.001 and x k+1 x k 0.001 for 1 k < m. 令 x = x m+1. 求 x. 用 while 寫法如下 : x <- 1 d <- 1 while ( d >= 0.001 ) x.new <- x - (x^2-2)/(2*x) d <- abs(x.new - x) x <- x.new x #x 用 repeat 加上 break 寫法如下 : x <- 1; d <- 1 repeat x.new <- x - (x^2-2)/(2*x) d <- abs(x.new - x) x <- x.new if (d < 0.001) break x #x 7