3.8 Good Programming Habits: T C Q Exists
3.8 Good Programming Habits: T C Q Exists
Good programming is clear rather than clever. Being clever is good, but given
a choice, being clear is preferable. The reason for this is that in practice much
more time is spent correcting and modifying programs than is ever spent
writing them, and if you are to be successful in either correcting or modifying
a program, you will need it to be clear.
You will find that even programs you write yourself can be very difficult to
understand after only a few weeks have passed.
We find the following to be useful guidelines: start each program with some
comments giving the name of the program, the author, the date it was written,
and what the program does. A description of what a program does should
explain what all the inputs and outputs are.
Variable names should be descriptive, that is, they should give a clue as to
what the value of the variable represents. Avoid using reserved names or func-
tion names as variable names (in particular t, c, and q are all function names
in R). You can find out whether or not your preferred name for an object is
already in use by the exists function.
Use blank lines to separate sections of code into related parts, and use in-
denting to distinguish the inside part of an if statement or a for or while
loop.
Document the programs that you use in detail, ideally with citations for spe-
cific algorithms. There is no worse feeling than returning to undocumented
code that had been written several years earlier to try to find and then ex-
plain an anomaly.
3.9 Exercises
Supposing that you are given x, write an R expression for y using if state-
ments.
Add your expression for y to the following program, then run it to plot the
function f .
# input
x.values <- seq(-2, 2, by = 0.1)
8
6
y.values
4
2
0
−2 −1 0 1 2
x.values
# output
plot(x.values, y.values, type = "l")
Your plot should look like Figure 3.2. Do you think f has a derivative at
1? What about at 0?
We remark that it is possible to vectorise the program above, using the
ifelse function.
!n
2. Let h(x, n) = 1 + x + x2 + · · · + xn = i=0 xi . Write an R program to
calculate h(x, n) using a for loop.
3. The function h(x, n) from Exercise 2 is the finite sum of a geometric se-
quence. It has the following explicit formula, for x ̸= 1,
1 − xn+1
h(x, n) = .
1−x
EXERCISES 45
Test your program from Exercise 2 against this formula using the following
values
x n h(x, n)
0.3 55 1.428571
6.6 8 4243335.538178
You should use the computer to calculate the formula rather than doing it
yourself.
4. First write a program that achieves the same result as in Exercise 2 but
using a while loop. Then write a program that does this using vector
operations (and no loops).
If it doesn’t already, make sure your program works for the case x = 1.
5. To rotate a vector (x, y)T widdershins (anticlockwise) by θ radians, you
premultiply it by the matrix
" #
cos(θ) − sin(θ)
.
sin(θ) cos(θ)
x <- 3
for (i in 1:3) {
show(x)
if (x[i] %% 2 == 0) {
x[i+1] <- x[i]/2
} else {
x[i+1] <- 3*x[i] + 1
}
}
show(x)
46 BASIC PROGRAMMING
(b). The second program implements the Lotka–Volterra model for a
‘predator-prey’ system. We suppose that x(t) is the number of prey
animals at the start of a year t (rabbits) and y(t) is the number of
predators (foxes), then the Lotka–Volterra model is:
x(t + 1) = x(t) + br · x(t) − dr · x(t) · y(t);
y(t + 1) = y(t) + bf · dr · x(t) · y(t) − df · y(t);
where the parameters are defined by:
br is the natural birth rate of rabbits in the absence of predation;
dr is the death rate per encounter of rabbits due to predation;
df is the natural death rate of foxes in the absence of food (rabbits);
bf is the efficiency of turning predated rabbits into foxes.
# program spuRs/resources/scripts/predprey.r
# Lotka-Volterra predator-prey equations
br <- 0.04 # growth rate of rabbits
dr <- 0.0005 # death rate of rabbits due to predation
df <- 0.2 # death rate of foxes
bf <- 0.1 # efficiency of turning predated rabbits into foxes
x <- 4000
y <- 100
while (x > 3900) {
# cat("x =", x, " y =", y, "\n")
x.new <- (1+br)*x - dr*x*y
y.new <- (1-df)*y + bf*dr*x*y
x <- x.new
y <- y.new
}
Note that you do not actually need to know anything about the pro-
gram to be able to chart its flow.
10. Write a program that uses a loop to find the minimum of a vector x, without
using any predefined functions like min(...) or sort(...).
You will need to define a variable, x.min say, in which to keep the small-
est value you have yet seen. Start by assigning x.min <- x[1] then use
a for loop to compare x.min with x[2], x[3], etc. If/when you find
x[i] < x.min, update the value of x.min accordingly.
11. Write a program to merge two sorted vectors into a single sorted vector.
Do not use the sort(x) function, and try to make your program as efficient
as possible. That is, try to minimise the number of operations required to
merge the vectors.
12. The dice game craps is played as follows. The player throws two dice, and if
the sum is seven or eleven, then he wins. If the sum is two, three, or twelve,
then he loses. If the sum is anything else, then he continues throwing until
he either throws that number again (in which case he wins) or he throws a
seven (in which case he loses).
EXERCISES 47
0
y
−1
−2
−3
−3 −2 −1 0 1 2 3
Write a program to simulate a game of craps. You can use the following
snippet of code to simulate the roll of two (fair) dice:
x <- sum(ceiling(6*runif(2)))
√
13. Suppose that (x(t), y(t)) has polar coordinates ( t, 2πt). Plot (x(t), y(t))
for t ∈ [0, 10]. Your plot should look like Figure 3.3.
14. Improve the code for program threexplus1.r as shown in Section 3.7.
Assume that the intermediary calls to show and cat are unnecessary.
15. A room contains 100 toggle switches, originally all turned off. 100 people
enter the room in turn. The first toggles every switch, the second toggles
every second switch, the third every third switch, and so on, to the last
person who toggles the last switch only.
At the end of this process, which switches are turned on?