Flow Control

R, like most programming languages, has the ability to control the execution of code with programming statements such as for, while,repeat, and break. As an example, consider how for is used in to add the values 10, 20, and 30.

sum.a <- 0
for(i in c(10, 20, 30)){
  sum.a <- i + sum.a
}
sum.a
[1] 60

The for statement allows one to specify that a certain operation will be repeated a fixed number of times. The syntax for the for statement is

for (name in vector) {
    statements
    }  

Statements can be grouped using braces {}. When several statements are grouped, the standard R syntax is to start with a left brace {, then place each statement on its own line and close the group of statements with a right brace } on its own line.

Example:

A Lucas number is defined as \[ L_n = \begin{cases} 2 & \text{if } n =1\\ 1 & \text{if } n =2\\ L_{n-1} + L_{n-2} & \text{if } n \geq 3. \end{cases} \] Use a for loop to compute the first 15 Lucas numbers.

The first 15 Lucas numbers after allocating space using the numeric() function for the answers.

Number <- 15              # Number of Lucas numbers desired 
Lucas <- numeric(Number)  # Storage for Lucas numbers
Lucas[1] <- 2             # First Lucas number 
Lucas[2] <- 1             # Second Lucas number
for(i in 3:Number){
  Lucas[i] <- Lucas[i - 1] + Lucas[i - 2]
}
Lucas
 [1]   2   1   3   4   7  11  18  29  47  76 123 199 322 521 843

The while statement is useful for repeating a set of statements when the exact number of repeats is not known in advance. The syntax for the while statement is while (condition) {statements}. The statements are evaluated as long as the condition is TRUE. Once the condition evaluates to FALSE, nothing more is done. An alternative to the while statement is the repeat statement with a break statement. The syntax for using a repeat statement is repeat {statements}. The statements generally include a break statement of the form if (condition) break. Statements are repeated as long as the condition is TRUE. Once the condition evaluates to FALSE, nothing more is done.

The square root of a positive number, \(x\), can be approximated iteratively using \(x_{n+1} = (x_n + x/x_n)/2\) where \(x_n\) is the initial guess for the value of \(\sqrt{x}\). Approximating the \(\sqrt{113734}\) to within 0.00001 can be accomplished using a while statement or a repeat statement. Using a while statement to approximate \(\sqrt{113734}\) to within a 0.00001 is shown below.

options(digits = 8)
x <- 113734
tolerance <- 0.00001
oldapp <- x/2
newapp <- (oldapp + x/oldapp)/2 
i <- 0
while( abs(newapp - oldapp) > tolerance){
  oldapp <- newapp
  newapp <- (oldapp + x/oldapp)/2
  i <- i + 1         # Iteration number
}
c(newapp, i)
[1] 337.24472  11.00000
options(digits = 7)  # reset to default

Using a repeat statement to approximate \(\sqrt{113734}\) to within a 0.00001 is shown next.

options(digits = 8)
x <- 113734
tolerance <- 0.00001
oldapp <- x/2
newapp <- (oldapp + x/oldapp)/2 
i <- 0
repeat{
  oldapp <- newapp
  newapp <- (oldapp + x/oldapp)/2
  i <- i + 1
  if(abs(newapp - oldapp) < tolerance)
    break
}
c(newapp, i)
[1] 337.24472  11.00000
options(digits = 7) # reset to default

The approximate \(\sqrt{113734}\) (337.24472) is achieved in \(i = 11\) iterations regardless of the type of statement used.

The if statement allows one to control which statements are executed. The syntax for the if statement has two forms:

if (condition) {statements when TRUE}

and

if (condition) {
statements when TRUE
} else {
statements when FALSE
}

One needs to pay close attention to how the second form is typed. In particular, entering

if(condition) {statements when TRUE}
else {statements when FALSE}

may not do what you expect. R will execute the first line before seeing the second line.

Example:

Write three separate programs to simulate throwing a pair of dice 99,999 times. Compute the mean of each of the 99,999 throws, and create a table of the means using a for loop, a while statement, and a repeat statement.

Solution:

The function sample() is used to sample 2 values with replacement from 1 to 6.

Using a for loop: Each time the loop cycles, the mean of the two dice is stored in the \(i^{\text{th}}\) position of the means vector. The tabled results are stored in T1 and subsequently printed.

set.seed(3)           # setting seed for reproducibility
N <- 10^5 - 1         # N = number of simulations
means <- numeric(N)   # Defining numeric vector of size N
for(i in 1:N){
  means[i] <- mean(sample(x = 1:6, size = 2, replace = TRUE))
  }
T1 <- table(means)
T1
means
    1   1.5     2   2.5     3   3.5     4   4.5     5   5.5     6 
 2802  5523  8394 11138 13938 16552 13876 11202  8287  5576  2711 

Using a while statement: The command matrix(0, N, 2) creates a 99,999 by 2 matrix of zeros. While \(i \leq N\), the results from simulating tossing two dice are stored in the \(i^\text{th}\) row of the N2mat matrix. The function apply() is used to compute the mean of each of the rows of N2mat and to store the result in the vector means. The tabled results are stored in T2 and subsequently printed.

set.seed(3)                 # setting seed for reproducibility
i <- 1
N <- 10^5 - 1               # N = number of simulations
N2mat <- matrix(0, N, 2)    # initialize N*2 matrix to all 0's
while(i <= N){
  N2mat[i, ] <- sample(x = 1:6, size = 2, replace = TRUE)
  i <- i + 1
}
means <- apply(N2mat, 1, mean)
T2 <- table(means)
T2
means
    1   1.5     2   2.5     3   3.5     4   4.5     5   5.5     6 
 2802  5523  8394 11138 13938 16552 13876 11202  8287  5576  2711 

Using a repeat statement: The line N2mat[i, ] <- sample(1:6, 2, replace = TRUE) is repeated, filling in the \(i^\text{th}\) row of the matrix with values that simulate throwing two dice until \(i = N\), at which point the repeat ends. The function apply() is used to compute the mean of each of the rows of N2mat and to store the result in the vector means. The tabled results are stored in T3 and subsequently printed.

set.seed(3)                  # setting seed for reproducibility
i <- 1
N <- 10^5 - 1                # N = number of simulations
N2mat <- matrix(0, N, 2)     # initialize N*2 matrix to all 0's
repeat{
  N2mat[i, ] <- sample(1:6, 2, replace = TRUE)
  if (i == N) break
  i <- i + 1
}
means <- apply(N2mat, 1, mean)
T3 <- table(means)
T3
means
    1   1.5     2   2.5     3   3.5     4   4.5     5   5.5     6 
 2802  5523  8394 11138 13938 16552 13876 11202  8287  5576  2711 

The function plot() is applied to T3 after dividing its contents by N.

par(yaxt = "n")
plot(T3/N, xlab = "Mean of Two Dice", ylab = "", 
     main="Simulated Sampling Distribution \n of the Sample Mean",
     ylim=c(0, 6.1/36), lwd = 2, cex.main = 1)
par(yaxt = "s")
axis(side = 2, at = c(0, 1/36, 2/36, 3/36, 4/36, 5/36, 6/36, 5/36, 4/36, 3/36, 2/36, 1/36), 
     labels = c("0","1/36", "2/36", "3/36", "4/36", "5/36", "6/36", "5/36", 
              "4/36", "3/36", "2/36", "1/36"), las=1 )
abline(h = c(0:6)/36, lty = 2, col = "gray")