Tutorial
Tutorial
Tutorial
i=1
(2i 1) = N
2
Write a program that uses a loop to print out the sequence of oating-point numbers:
1, 1 +
1
1
, 1 +
1
1 +
1
1
, 1 +
1
1 +
1
1+
1
1
, 1 +
1
1 +
1
1+
1
1+
1
1
, . . .
(Print out the rst 20 terms.) If you would like to see more digits of precision than the
default (6), see the output formatting instructions on page 84.
40
Modify your program so that it reads in a number x from the user, then prints out the
sequence of oating-point numbers:
x, x +
1
x
, x +
1
x +
1
x
, x +
1
x +
1
x+
1
x
, x +
1
x +
1
x+
1
x+
1
x
, . . .
What does this sequence
2, 2 +
1
2
, 2 +
1
2 +
1
2
, 2 +
1
2 +
1
2+
1
2
, 2 +
1
2 +
1
2+
1
2+
1
2
, . . .
tend to?
Write a program that uses a loop to print out the sequence of oating-point numbers:
1,
_
1 +
1,
_
1 +
_
1 +
1,
1 +
_
1 +
_
1 +
1, . . .
What does this sequence tend to? The square root function in C++ is called sqrt(....).
To tell the C++ compiler that you want to use maths functions such as sqrt you must put
#include <cmath> at the top of your program, before or after the #include <iostream>
statement.
Optional: Write a program that prints out all prime numbers less than or equal to N.
Hint: use the modulo division operator (%).
9.3 Tips
1. Start with a working program
The easiest way to write programs is to modify the existing programs. Make small modi-
cations, compiling whenever possible.
2. Making modications
Mentally check that the program is doing what it is required to do.
Check that your program is laid out correctly with indentation at the beginning and
semi-colons at the end of each statement.
Include comment statements to help you and others understand what the program is
doing.
3. Checking syntax
Compile, using g++ -Wall or make. If there are no syntax errors, the program will compile
successfully. One or more errors will cause the compiler to print out error or warning
messages, which will be listed along with program line numbers indicating where the error
occurred. Remember the tips on page 18 always use warnings when compiling. And
save typing by using make.
41
4. Compilation errors
Dont be worried by the number of error messages. The compiler is trying to give as much
help as it can. You can get a lot of error messages from just one mistake so always look
at the rst error message rst.
Find the line in the le to which it refers (there is a Goto-line option on the editor Edit
menu) and try to correct it. Often, the compiler will report that the error is in a line just
after the one in which there was a mistake. If you cannot spot the mistake straight away,
look at neighbouring lines.
The most common errors will be due to undeclared variables or variables incorrectly declared,
and missing or incorrect punctuation. If you are feeling stuck, a really good way to track
down the cause of an error message is to explain to a friend, step by step, how you modied
a compilable program to get the program with the compilation error.
5. Debugging tips
You dont need to close the editor each time you save the le and recompile; you should
have only one copy of Emacs running at any time.
Continue with this compile/debug/edit procedure until your program compiles successfully.
6. Finding logical errors
Run your program and check that it gives the correct answer.
9.4 Assessment
Heres the self-assessed bit.
Set yourself an additional programming task along the lines of the preceding
tasks, and solve it by yourself. Then submit your task statement and the sourcecode
of your solution in the same manner as described for SESSION 1.
If you nish SESSION 2 with time to spare, why not make a start on SESSION 3 ?
END OF SESSION 2
42
Part IB Computing Course 2011
PRACTICAL SESSION 3
10 Instructions
10.1 Objectives
Here we will test our understanding of:
Boolean expressions with relational operators
Simple control structures for selection and repetition
You will now use these skills in the following computing exercises. Youll also learn to use the
graphing program, gnuplot.
10.2 Computing Exercises
Reminder: programming in pairs is a very good idea, as long as the weaker programmer does the
typing.
10.2.1 Simple Monte Carlo
Monte Carlo methods use random numbers to generate approximate answers to mathematical
questions. A good Monte Carlo method has the property that the more random numbers are
used, the more accurate the answer becomes.
The program RandDemo6.cc on the next page shows how to generate N pairs (x, y) uniformly
distributed in the unit square, and test whether each pair is in the unit circle or not. The variable
N is supplied by the user on the command line. (I recommend this non-interactive method of
getting inputs from the user, rather than cin.) This program has several other new features,
some of which well explain later. For the moment, dont worry about the lines with #include,
#define, using, or sscanf.
Make sure you understand everything inside the main for loop.
The program uses the ternary conditional operator ? in the assignment
outcome = ( x*x + y*y < 1.0 ) ? 1 : 0
In general,
outcome = ( expression1 ) ? expression2 : expression3
means that outcome is set equal to expression2 if expression1 is true, and to expression3 if
expression1 is false.
Rewrite the program so as to use an if-else in place of this ternary conditional. Explain to
a friend how the program works.
When RandDemo6 runs, the last two columns of its output contain the values of N and 4.0 * fraction_in
What do you expect the value of 4.0*fraction_in to do as N gets big? (If necessary,
recall one of the demos in the introductory lectures of the course.)
43
// RandDemo6.cc
// usage:
// ./RandDemo6 [<N> [<seed>]]
// example:
// ./RandDemo6 (Run with default value of N and seed)
// ./RandDemo6 30 9237832 (Run with N=30 and seed=9237832)
// * uses random() to get a random integer
// * gets parameters from command line
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
#define ranf() \
((double)random()/(1.0+(double)0x7fffffff)) // Uniform from interval [0,1)
// obtained by division by 2**31
int main(int argc, char* argv[])
{
int outcome, N=10, count_in=0 , seed=123 ;
double fraction_in ;
if(argc>1) {
sscanf( argv[1], "%d", &N ) ; // put the first command-line argument in N
}
if(argc>2) {
sscanf( argv[2], "%d", &seed ) ; // put the 2nd argument in seed
}
// Write out a summary of parameters
cout << "# " << argv[0] << " N=" << N << " seed=" << seed << endl ;
// Initialise random number generator
srandom(seed);
// Perform N experiments.
for(int n=1; n<=N; n++) {
double x = ranf(); // ranf() returns a real number in [0,1)
double y = ranf();
outcome = ( x*x + y*y < 1.0 ) ? 1 : 0 ;
count_in += outcome ;
//Integer variables must be converted (cast) for correct division
fraction_in = static_cast<double>(count_in)/n;
cout << "Location" << outcome << "\t" << x << "\t" << y << "\t"
<< count_in << "\t" << n << "\t" << 4.0 * fraction_in << endl;
}
return 0;
}
44
When you are running a program in a terminal (also known as a shell), the symbol > can be
used to redirect the output of the program to a le. Send the output of RandDemo6 to a le, using,
say,
./RandDemo6 20 2389 > tmpfile
Start gnuplot by typing gnuplot in a terminal. When it has started, gnuplot gives you a prompt,
which looks like this: gnuplot>. Plot the generated points (x, y) using, for example,
gnuplot> plot tmpfile u 2:3 w points
What we mean here is please type plot tmpfile u 2:3 w points. gnuplot has many
options for making nice plots. Type help to get help. You can change the options interactively
for example,
gnuplot> set size square
gnuplot> replot
but I recommend writing the gnuplot commands in a plain text le say splat.gnu and then
loading the commands thus
gnuplot> load splat.gnu
Putting the commands in a le has the advantage that you then have a permanent record of how
a plot was generated, should you want to replot or modify it in the future.
Unix provides many utilities for dealing with textles. When you are doing scientic com-
putation, we recommend that you write the results of the computation out in plain text les,
then handle subsequent inspection or processing of the results with other programs rather than
writing a single monolithic program that does everything. Heres an example. First run in your
terminal:
./RandDemo6 200 1234321 > tmpfile
which puts 200 outcomes in tmpfile. Now in your terminal run
grep Location1 tmpfile > file1
grep -v Location1 tmpfile > file0
The rst grep command looks at every line in tmpfile and prints out the lines that contain the
string Location1. The output went into le1 because of the redirect (>). You can check what
happened with the command:
more file1
The second command uses grep with a special ag -v, which means invert the match. Every
line in tmpfile that does not contain the string Location1 gets printed.
Use file0, file1, and gnuplot to make a pretty picture that you could use to explain to
someone how this Monte Carlo method can be used to estimate . By the way, gnuplot can
easily plot functions as well as datales. For example,
gnuplot> plot sqrt(1-x*x) with line 3
45
plots the function
1 x
2
with a line of colour 3 (which might be blue). gnuplot always calls
the variable on the horizontal axis x. You can grab a screenshot of your pretty picture with the
terminal command: import pretty.png or by typing gnome-screenshot in a terminal. Note
that these are terminal commands, not gnuplot commands!
Having generated N points, whats the estimate of ? How close do you expect this estimate to
be to the true value? Write down the expected error (N) of the estimate as a function
of N.
Use gnuplot to plot (N) as a function of N.
You can dene and plot functions in gnuplot like this:
gnuplot> f(N) = 1.0/N
gnuplot> set xrange [1:200]
gnuplot> plot pi+f(x) with line 5, pi-f(x) with line 5
NB: the function f(N) is not the answer to the question above.
Now superpose your plot of the theoretical prediction about the estimate [ (N)] on the
Monte Carlo estimate (column 6) as a function of N. The estimate can be plotted with
plot tmpfile u 5:6 with linespoints
Does the Monte Carlo method work as expected? How many points are required to get
an answer thats probably accurate to 1%? Do a couple of runs of that length, putting the
outputs in separate les (say tmpfile1 and tmpfile2), and see what happens. Zoom in on the
interesting yrange. (You may be able to zoom in to a plot by right-clicking on the gnuplot display.
Alternatively, use set yrange [3.1:3.2].)
The output les may get rather large, and slow to plot. Modify your C++ program so
that rather than printing a line for every outcome, it prints a gradually decreasing
fraction of the lines as n increases.
How many points are required to get an answer thats probably accurate to 2 decimal places?
To 0.1%? Make a prediction, then check it.
Exercise: Now write a program that estimates ln(2) to 2 decimal places by a
Monte Carlo method.
[Hint: you may nd the function y = 1/x interesting to think about.]
10.3 Assessment
If you solved the previous ln(2) exercise by yourself, then please submit your so-
lution to it as you piece of assessed work. It is important that you briey describe
your approach, and include a statement that you made the solution yourself. Submit
this in the usual manner.
If on the other hand, you didnt solve the ln(2) exercise by yourself, please set
yourself an additional programming task along the lines of the preceding tasks,
and solve it by yourself. Then submit your task statement and your solution to that
task instead, making sure to describe it well.
10.3.1 More ecient Monte Carlo (optional exercise)
How can you modify the Monte Carlo method to reduce the number of random numbers required
to obtain ln(2) to a given accuracy?
46
10.3.2 Comment
A Monte Carlo approach seems a pretty goofy way to evaluate an integral, but in high-dimensional
problems in statistical physics, quantum physics, and statistical inference, Monte Carlo methods
are very widely used. See Information Theory, Inference, and Learning Algorithms, David J.C.
MacKay, Cambridge University Press (2003) available free online at www.inference.phy.cam.
ac.uk/mackay/itila or tinyurl.com/d6vck for further reading about modern Monte Carlo
methods.
10.3.3 Testing for randomness (optional exercise)
Returning to the points (x, y) that you plotted a couple of pages ago: do you think these plot-
ted points (x, y) look like perfectly random points? If you think not, dene a measure of non-
randomness that captures what you think is wrong with the so-called random points, and write a
program to measure this quantity for the points generated by the random() routine.
10.3.4 Estimating the value of II (optional exercise)
Write a program to print out the rst N terms in the series:
N
i=1
1
i
2
= 1 +
1
4
+
1
9
+
1
16
+ . . . +
1
N
2
The number of terms, N, is to be input by the user at the keyboard or on the command line.
Modify your program so that for each value of the index i, it evaluates the sum of the rst i
terms.
The sum of this series can be shown (Leonhard Euler (1707-1783)) to converge to
2
/6. Make
another modication to your program so that at each iteration the estimate of is printed along-
side the sum. [To use the mathematical library function sqrt() you must include the header
le cmath at the top of your program.] Plot the estimate as a function of N. How good is the
estimate of after N=100 iterations? How many iterations are needed to get an estimate of that
is accurate to 2 decimal places?
If you nish SESSION 3 with time to spare, why not make a start on SESSION 4 ?
END OF SESSION 3
47
11 Functions
Computer programs that solve real-world problems are usually much larger than the simple pro-
grams discussed so far. To design, implement and maintain larger programs it is necessary to break
them down into smaller, more manageable pieces or modules. Dividing the problem into parts and
building the solution from simpler parts is a key concept in problem solving and programming.
In C++ we can subdivide the functional features of a program into blocks of code known as
functions. In eect these are subprograms that can be used to avoid the repetition of similar
code and allow complicated tasks to be broken down into parts, making the program modular.
Until now you have encountered programs where all the code (statements) has been written
inside a single function called main(). Every executable C++ program has at least this function.
In the next sections we will learn how to write additional functions.
11.1 Function denition
Each function has its own name, and when that name is encountered in a program (the function
call), execution of the program branches to the body of that function. After the last statement of
the function has been processed (the return statement), execution resumes on the next line after
the call to the function.
Functions consist of a header and a body. The header includes the name of the function and
tells us (and the compiler) what type of data it expects to receive (the parameters) and the type
of data it will return (return value type) to the calling function or program.
The body of the function contains the instructions to be executed. If the function returns a
value, it will end with a return statement. The following is a formal description of the syntax for
dening a function:
return-value-type function-name (parameter-list )
{
declaration of local variables ;
statements ;
return return-value ;
}
The syntax is very similar to that of the main program, which is also a function. main() has
no parameters and returns the integer 0 if the program executes correctly. Hence the return value
type of the main() function is int.
int main()
{
declarations ;
statements ;
return 0;
}
48
11.2 Example of function denition, declaration and call
Let us rst look at an example of program written entirely in the function main() and then we
will modify it to use an additional function call.
We illustrate this with a program to calculate the factorial (n!) of an integer number (n) using
a for loop to compute:
n! = 1 2 3 . . . (n 2) (n 1) n
// MainFactorial.cc
// Program to calculate factorial of a number
#include <iostream>
using namespace std;
int main()
{
int number=0, factorial=1;
// User input must be an integer number between 1 and 10
while(number<1 || number>10)
{
cout << "Enter integer number (1-10) = ";
cin >> number;
}
// Calculate the factorial with a FOR loop
for(int i=1; i<=number; i++)
{
factorial = factorial*i;
}
// Output result
cout << "Factorial = " << factorial << endl;
return 0;
}
Even though the program is very short, the code to calculate the factorial is best placed inside a
function since it is likely to be executed many times in the same program or in dierent programs
(e.g., calculating the factorials of many dierent numbers, computing binomial coecients and
permutations and combinations).
49
// FunctionFactorial.cc
// Program to calculate factorial of a number with function call
#include <iostream>
using namespace std;
// Function declaration (prototype)
int Factorial(int M);
int main()
{
int number=0, result;
// User input must be an integer number between 1 and 10
while(number<1 || number>10)
{
cout << "Integer number = ";
cin >> number;
}
// Function call and assignment of return value to result
result = Factorial(number);
//Output result
cout << "Factorial = " << result << endl;
return 0;
}
// Function definition (header and body)
// An integer, M, is passed from caller function.
int Factorial(int M)
{
int factorial=1;
// Calculate the factorial with a FOR loop
for(int i=1; i<=M; i++)
{
factorial = factorial*i;
}
return factorial; // This value is returned to caller
}
Three modications to the program have been made to incorporate a function. If we look at
the modied sample program, FunctionFactorial.cc, we nd:
50
1. The declaration of the function above the main program. The declaration (also known as
the prototype) tells the compiler about the function and the type of data it requires and will
return on completion.
2. The function call in the main body of the program determines when to branch to the
function and how to return the value of the data computed back to the main program.
3. The denition of the function Factorial() below the main program. The denition con-
sists of a header, which species how the function will interface with the main program,
and a body, which lists the statements to be executed when the function is called.
Before a function can be used it must be declared (0), usually at the top of the program le.
9
When the function name is encountered in the main body of the program (1), execution branches
to the body of the function denition (2). Copies of the values of function arguments are stored
in the memory locations allocated to the parameters. The statements of the function are then
executed (3) up to the rst return statement when control returns to the main body (4). Any
value returned by the function is stored by an assignment statement. Execution in the main body
is resumed immediately after the function call (5).
// Function declaration
int Factorial(int M);
int main()
{
// Function call
result = Factorial(number);
return 0;
0
}
// Function definition
int Factorial(int M)
{
return factorial;
}
1
3
4
5
2
11.3 Function header and body
The function is dened below the body of main(). The header in this example:
int Factorial(int M)
9
Strictly speaking, its not always essential to declare a function before it is used, as long as the compiler
encounters the functions denition before the function is used.
51
indicates that the Factorial() function expects to be passed an integer value (the parameter
type) from the main body of the program and that the value passed will be stored locally in a
variable named M (the formal parameter name). The return value type of the function is also int
in this example, indicating that at the end of executing the body of the function, an integer value
will be returned to the statement in which the function was called. Functions that do not return
a value have return value type void.
The body of the function computes the factorial of a number in exactly the same way as in
the example with only a main() function. The execution of the function terminates with a return
statement:
return factorial;
which species that the value stored in the function variable factorial should be passed back to
the calling function.
11.4 Function declaration
Every function should be declared before it is used. The declaration tells the compiler the name,
return value type and parameter types of the function. In this example the declaration:
int Factorial(int M);
tells the compiler that the program passes the value of an integer to the function and that the
return value must be assigned to an integer variable. The declaration of a function is called its
prototype, which means the rst time the function is identied to your program.
The function prototype and the function denition must agree exactly about the return value
type, function name and the parameter types. The function prototype is usually a copy of the
function header followed by a semicolon to make it a declaration and placed before the main
program in the program le.
11.5 Function call and execution
The function denition is entirely passive. By itself it does nothing unless instructed to execute.
This is done by a statement in the main program called the function call.
For example the statement:
result = Factorial(number);
calls the function Factorial() and passes a copy of the value stored in the variable, number. When
the function is called, computer memory is allocated for the parameter, M, and the value passed is
copied to this memory location. Memory is also allocated to the (local) variables factorial and
i. The statements of the function are then executed and assign a value to the variable factorial.
The return statement passes this value back to the calling function. The memory allocated to the
parameters and local variables is then destroyed. The value returned is assigned to the variable on
the left-hand side, result, in the expression used to call the function. The net eect of executing
the function in our example is that the variable result has been assigned the value of the factorial
of number.
A function can be called any number of times from the same or dierent parts of the program.
It can be called with dierent parameter values (though they must be of the correct type). For
example the following fragment of code can be used to print out the factorials of the rst 10
integers:
52
for(int i=1; i<=10; i++)
{
result = Factorial(i);
cout << i << "! = " << result << endl;
}
and:
binomialCoefficient = Factorial(n)/(Factorial(k) * Factorial(n-k));
can be used to compute the binomial coecient:
n!
k!(n k)!
(though this is not the best way to compute a binomial coecient!).
11.6 Function arguments
The names of variables in the statement calling the function will not in general be the same as the
names in the function denition, although they must be of the same type. We often distinguish
between the formal parameters in the function denition (e.g. M) and the actual parameters
for the values of the variables passed to the function (e.g. number in the example above) when it
is called.
Function arguments (actual parameters) can include constants and mathematical expressions.
For example the following statement assigns the value 24 to the variable result.
result = Factorial(4);
The function arguments can also be functions that return an appropriate value (for example
Factorial(Factorial(4)), although this concise style makes the code harder to read and debug.
53
11.7 Another example
Here is is another example of the declaration, denition and call of a function, AreaTriangle(), in
a program to calculate the area of a regular hexagon inscribed in a circle of radius input by the user.
// HexagonValue.cc
// Program to calculate the area of a regular hexagon inscribed in a
// circle as sum of areas of 6 triangles by calling AreaTriangle()
#include <iostream>
using namespace std;
// AreaTriangle function prototype
float AreaTriangle(float base, float height);
int main()
{
float side, segmentHeight, hexagonArea;
float cosTheta = 0.866025;
cout << "Program to calculate the area of a hexagon" << endl;
cout << "Enter side of hexagon: ";
cin >> side;
// Base of triangle is equal to side, height is side*cos(30)
segmentHeight = side*cosTheta;
// Function returns area of segment. 6 segments for total area.
hexagonArea = 6.0 * AreaTriangle(side,segmentHeight);
cout << "Area of hexagon = " << hexagonArea << endl;
return 0;
}
// AreaTriangle function definition
float AreaTriangle(float base, float height)
{
float area;
area = (base*height)/2.0;
return area;
}
The statement:
hexagonArea = 6.0 * AreaTriangle(side,segmentHeight);
calls the function to calculate the area of a triangle with base and height given by the values stored
in side and segmentHeight and then assigns the value of 6 times the area (the return value of
the function) to the variable hexagonArea. It is therefore equivalent to the following:
54
segmentArea = AreaTriangle(side,segmentHeight);
hexagonArea = 6.0*segmentArea;
11.8 Passing by value or reference
There are two ways to pass values to functions. Up to now we have looked only at examples of
passing by value. In the passing by value way of passing parameters, a copy of the variable
is made and passed to the function. Changes to that copy do not aect the original variables
value in the calling function. This prevents the accidental corrupting of variables by functions
and so is often the preferred method for developing correct and reliable software systems. One
disadvantage of passing by value however, is that only a single value can be returned to the caller.
If the function has to modify the value of an argument or has to return more than one value, then
another method is required.
An alternative uses passing by reference in which the function is told where in memory the
data is stored (i.e., the function is passed the memory address of the variables). In passing the
address of the variable we allow the function to not only read the value stored but also to change
it.
Heres an analogy. When you tell a friend about a webpage on the course wiki, you can either
print out a copy of the webpage for them; or you can send them the URL of the webpage. Giving
them the copy is pass by value; giving them the URL is pass by reference. When you pass by
value, they can manipulate their copy of the page, and their manipulations have no eect on the
original page. When you pass by reference, they will be able to edit the contents of the webpage.
There are two ways to pass a parameter by reference. The simple (and rather subtle) way is
described here in the example SortReference.cc. An alternative approach to passing by reference
is demonstrated on the web in SortReference2.cc. (http://tinyurl.com/38fp68)
To indicate that a function parameter is passed by reference the symbol & is placed next to the
variable name in the parameter list of the function denition and prototype (but not the function
call). Inside the function the variable is treated like any other variable. Any changes made to it,
however, will automatically result in changes in the value of the variable in the calling function.
A simple example of passing by reference is given below for a function that swaps the values
of two variables in the calling functions data by reading and writing to the memory locations of
these variables. Note that the parameters are mentioned only by name in the function call. This
appears to be the same as calling by value. The function header and prototype, however, must use
the & symbol by the variable name to indicate that the call is by reference and that the function
can change the variable values.
55
// SortReference.cc
// Program to sort two numbers using call by reference.
// Smallest number is output first.
#include <iostream>
using namespace std;
// Function prototype for call by reference
void swap(float &x, float &y);
int main()
{
float a, b;
cout << "Enter 2 numbers: " << endl;
cin >> a >> b;
if(a>b)
swap(a,b);
// Variable a contains value of smallest number
cout << "Sorted numbers: ";
cout << a << " " << b << endl;
return 0;
}
// A function definition for call by reference
// The variables x and y will have their values changed.
void swap(float &x, float &y)
// Swaps x and y data of calling function
{
float temp;
temp = x;
x = y;
y = temp;
}
12 Math library and system library built-in functions
Functions come in two varieties. They can be dened by the user or built in as part of the
compiler package. As we have seen, user-dened functions have to be declared at the top of the
le. Built-in functions, however, are declared in header les using the #include directive at the
top of the program le, e.g. for common mathematical calculations we include the le cmath with
the #include <cmath> directive, which contains the function prototypes for the mathematical
functions in the cmath library.
56
12.1 Mathematical functions
Math library functions allow the programmer to perform a number of common mathematical
calculations:
Function Description
sqrt(x) square root
sin(x) trigonometric sine of x (in radians)
cos(x) trigonometric cosine of x (in radians)
tan(x) trigonometric tangent of x (in radians)
exp(x) exponential function
log(x) natural logarithm of x (base e)
log10(x) logarithm of x to base 10
fabs(x) absolute value (unsigned)
ceil(x) rounds x up to nearest integer
floor(x) rounds x down to nearest integer
pow(x,y) x raised to power y
12.2 Random numbers
Other header les that contain the function prototypes of commonly used functions include
cstdlib and time. These contain functions for generating random numbers and for manipulating
time and dates respectively. If you want to use these functions then you would need to have lines
like #include <cstdlib> or #include <ctime> at the top of your program.
The function random() randomly generates an integer between 0 and the maximum value that
can be stored as an integer. Every time the function is called:
randomNumber = random();
a dierent number will be assigned to the variable randomNumber. Each number is supposed to
have an equal chance of being chosen each time the function is called. The details of how the
function achieves this will not be discussed here.
Before a random number generator is used for the rst time it should be initialised by giving
it a number called the seed. Each seed will result in a dierent sequence of numbers. The function
srandom() initialises the random number generator, random(). It must be called with an arbitrary
integer parameter (the seed). If you want fresh random numbers every time, you can conveniently
generate a fresh seed by using the value returned by the system clock function time() with the
parameter NULL. This returns the calendar time in seconds, converted to an integer value. The
following call, which is usually used only once, can be used to initialise the random number
generator:
srandom(time(NULL));
Alternatively, if you want to make random experiments that can be exactly reproduced, you might
prefer to give the user explicit control of the seed.
The RandDemo6.cc program used these system functions. Heres another example.
57
// Function to simulate rolling a single 6-sided die.
// Function takes no arguments but returns an integer.
// Each call will randomly return a different integer between 1 and 6.
int RollDie()
{
int randomNumber, die;
randomNumber = random();
die = 1 + (randomNumber % 6);
return die;
}
12.3 How can I nd out what library a function is in?
Sometimes you know the name of a function you want to use (e.g. cosh) but dont know the name
of the library it might be in. There is a simple unix terminal command that will tell you straigt
away. For example, to nd out which library cosh(x) is in, and how to use it, type man 3 cosh
into a terminal window, and you should see a response looking something like this:
COSH(3) Linux Programmers Manual COSH(3)
NAME
cosh, coshf, coshl - hyperbolic cosine function
SYNOPSIS
#include <math.h>
double cosh(double x);
float coshf(float x);
long double coshl(long double x);
Link with -lm.
DESCRIPTION
The cosh() function returns the hyperbolic cosine of x,
which is defined mathematically as (exp(x) + exp(-x)) / 2.
CONFORMING TO
SVr4, POSIX, 4.3BSD, C99. The float and the long double
variants are C99 requirements.
SEE ALSO
acosh(3), asinh(3), atanh(3), ccos(3), sinh(3), tanh(3)
2002-07-27 COSH(3)
58
which indicates not only the name of the header le you will have to include (in this case math.h)
but also supplied info on related functions that are in the same library. Press Q to quit viewing
this manual page.
59
Part IB Computing Course 2011
PRACTICAL SESSION 4
13 Instructions
13.1 Objectives
After reading through sections 7 and 8 of the tutorial guide and studying and executing the C++
programs in the examples (boxed) you should now be familar with
Denition, declaration and calling of functions
Passing values to and returning values from functions
Math and system library functions
You will now use these skills in the following computing exercises. The information in sections C
and D will help you to think about what is involved in producing a working solution. Suggestions
for the algorithms (mathematical recipes) and their implementation in C++ are provided.
13.2 Computing Exercises
13.2.1 Finding a solution to f(x) = 0 by iteration
Write a function that computes the square root of a number in the range 1 < x 100
with an accuracy of 10
4
using the bisection method. The Math library function must
not be used.
Test your function by calling it from a program that prompts the user for a single
number and displays the result.
Modify this program so that it computes the square roots of numbers from 1 to 10. Com-
pare your results with the answers given by the sqrt() mathematical library function.
13.3 The bisection method
The problem of nding the square root of a number, c, is a special case of nding the root of a
non-linear equation of the form f(x) = 0 where f(x) = c x
2
. We would like to nd values of x
such that f(x) = 0.
A simple method consists of trying to nd values of x where the function changes sign. We
would then know that one solution lies somewhere between these values. For example: If f(a)
f(b) < 0 and a < b then the solution x must lie between these values: a < x < b. We could then
try to narrow the range and hopefully converge on the true value of the root. This is the basis of
the so-called bisection method.
The bisection method is an iterative scheme (repetition of a simple pattern) in which the
interval is halved after each iteration to give the approximate location of the root. After i iterations
the root (lets call it x
i
, i.e., x after i iterations) must lie between
a
i
< x
i
b
i
60
and an approximation for the root is given by:
p
i
=
(a
i
+ b
i
)
2
where the error between the approximation and the true root,
i
, is bounded by:
i
=
(b
i
a
i
)
2
=
(b
1
a
1
)
2
i
.
At each iteration the sign of the functions f(a
i
) and f(p
i
) are tested and if f(a
i
) f(p
i
) < 0
the root must lie in the half-range a
i
< x < p
i
. Alternatively the root lies in the other half (see
gure). We can thus update the new lower and upper bound for the root:
if f(a
i
) f(p
i
) < 0 then a
i+1
= a
i
and b
i+1
= p
i
else a
i+1
= p
i
and b
i+1
= b
i
The bisection method is guaranteed to converge to the true solution but is slow to converge
since it uses only the sign of the function. An alternative is the NewtonRaphson method, which
takes into account the gradient of the function, f
f(p
i
)
f
(p
i
)
.
13.4 Notes on algorithm and implementation
0 1 2 3 4 5 6 7 8 9 10 11
60
40
20
0
20
40
60
p a b
f(p)
f(a)
f(b)
c
The square root of a number will be found by calling a user-dened function to implement
one of the iterative algorithms (i.e., repetition of a pattern of actions) described above. Review
tutorial section 11, which describes how to dene a function and how to pass parameters to the
function and return values to the main program.
61
You are required to dene a function to nd the square root of a number c, i.e., nd the zeroes
of f(x) = c x
2
. Your solution is to be accurate to 5 decimal places. Since the number input by
the user is between 1 and 100 the root will satisfy 0 < x 10 and a valid initial guess for the
lower and upper bound for the solution will always be a
1
= 0.1 and b
1
= 10.1. The error after
i iterations will be
10
2
i
. To produce a solution that is accurate to 5 decimal places we will need
more than 20 iterations.
1. Getting Started:
Start with a very simple program that prompts the user for the value of a real number in
the range 1 < c 100. Alternatively, steal RandDemo6.ccs method of getting the oat
c from the command-line (something like sscanf(..., "%f", &c), and not forgetting to
#include the relevant headers).
2. Function denition
You are required to dene a function, MySquareRoot(), which is passed the number (i.e., a
single parameter of type float) and returns the approximate value of its square root (i.e.,
return value type is float).
The C++ code for the function should be placed below the body of main(). Begin the
implementation of the function by typing in the function header and the opening and closing
braces. For example:
float MySquareRoot(float square)
{
// Body of function definition
}
3. Function body and implementation of algorithm
Inside the body of the function (i.e., after the opening brace):
(a) You will need to declare local variables to store the values of a
i
, b
i
, p
i
and f(a
i
) f(p
i
).
For example: lower, upper, root and sign. Initialize the values of lower and upper to
0.1 and 10.1 respectively. (A possible additional programming goal would be to make a
smarter initialization method such that square roots can be found for any c in a larger
range.)
(b) Set up a loop using the while or for repetition control statements to repeat the fol-
lowing algorithm (bisection method) at least 20 times.
(c) In each execution of the loop:
Estimate the value of the root as the average of the lower and upper bounds. Store
this value in variable root.
Evaluate the function at the current value of lower (i.e., a
i
) and at the current
estimate of the root, (p
i
).
Evaluate f(a
i
) f(p
i
) and store this value in variable sign.
Depending on the value of sign update the lower and upper bounds by the bisection
method described above.
(d) The function must end with a return statement to pass back the approximate value
of the square root.
62
4. Function declaration:
Declare the function by including the function prototype before main(). Compile your
program to make sure you have not made any typing or syntax errors.
5. Testing of function:
Call your function from your program with the (actual) parameter, e.g. number. The return
value of the function is to be assigned to a variable (e.g. squareRoot) which should also be
declared in main():
squareRoot = MySquareRoot(number);
Test your function creatively.
6. Loop
Set up a loop in the main routine to call the function 10 times to calculate the square roots
of the integers 1, 2, . . . 10.
13.5 Assessment
Set yourself an additional programming task along the lines of the preceding
tasks, and solve it by yourself. Then submit your task statement and your solution
in the usual manner.
If you nish SESSION 4 with time to spare, why not start to prepare for the remaining two
assessments? They are harder than those we have done so far, and gain more credit.
END OF SESSION 4
63
13.6 Have I done enough?
If you nd yourself asking Have I done enough for this weeks session?, the answer is please
self-assess! Do you feel youve got a rm grasp of all the highlighted concepts? If so, then thats
enough. One thing to check is have I developed my understanding of this weeks physics topic?
Thats one of the aims this term to get fresh insights into orbits, dynamics, waves, statistical
physics, pressure, temperature, and so forth.
64
More programming concepts
The new programming tools well use now are arrays (great for representing vectors, or lists of
similar things); structures (great for organizing things that belong together, such as a particles
position, mass, and velocity, or a vector and its range of indices); and how to modularize your
code.
We now cover the following topics.
arrays how to allocate memory on the y for
things like vectors
modularizing chopping up your code so you can reuse it
elegantly
structures and packages how to use structures in your elegant mod-
ules
formatted output getting the number of decimal places that
you want
14 Arrays
More realistic programs need to store and process a substantial number of items of data. The
types of variable considered so far have been simple data types capable of holding a single value.
Arrays are a consecutive group of variables (memory locations) that all have the same type and
share a common name. In many applications, arrays are used to represent vectors and matrices.
We now describe a simple approach to arrays. A more elegant approach will be described in due
course.
14.1 Declaration
An array is declared by writing the type, followed by the array name and size (number of elements
in the array) surrounded by square brackets.
type array-name [number-elements ];
float position[3];
int count[100];
char YourSurname[50];
The above examples declare position to be an array that has 3 elements which are real
numbers (e.g., 3D vector). YourSurname contains 50 characters (e.g., storing a surname) and
count is an array of 100 integer values.
An array can have any legal variable name but it cannot have the same name as an existing
variable. The arrays size is xed when the array is declared and remains the same throughout
the execution of the program.
14.2 Array elements and indexing
To refer to a particular element of the array we specify the name of the array and the position
number or index of the particular element. Array elements are counted from 0 and not 1. The
65
rst elements will always have position and index 0 and the last element will have index number
(position) N-1 if the array has N elements.
The rst elements in the arrays declared above are referred to by position[0], count[0] and
YourSurname[0] respectively. The last element of an array declared as array[N] with N elements
is referred to by array[N-1]. The last elements of the example arrays above are therefore referred
to by position[2], count[99] and YourSurname[49] respectively.
The index of an array can also be an expression yielding an integer value.
14.3 Assigning values to array elements
Elements of an array can be treated like other variables but are identied by writing the name of
the array followed by its index in square brackets. So for instance the statements:
marks[1] = 90.0;
scaled[1] = (marks[1] - mean)/deviation;
show how the second element of an array called marks is assigned a value and how the second
element of the array scaled is assigned the result of a calculation using this element value.
What is useful about arrays is that they t well with the use of loops. For example:
int count[100];
for(int i=0; i< 100; i++)
{
count[i] = 0;
}
can be used to initialise the 100 elements of an integer array called count by setting them all
to 0. The following program uses arrays and loops to calculate the scalar product of two vectors
input by the user.
66
// ScalarProduct.cc
// Calculating the scalar product between vectors input by user
#include <iostream>
using namespace std;
int main()
{
float vectorA[3], vectorB[3], scalar=0.0;
// Get input vectors from user.
cout << "Enter elements of first vector: " << endl;
for(int i=0;i<3;i++)
{
cin >> vectorA[i];
}
cout << "Enter elements of second vector: " << endl;
for(int i=0;i<3;i++)
{
cin >> vectorB[i];
}
// Calculate scalar product.
for(int i=0;i<3;i++)
{
scalar = scalar + (vectorA[i] * vectorB[i]);
}
// Output result.
cout << "The scalar product is " << scalar << endl;
return 0;
}
Note: care must be taken never to try to assign array elements that are not dened. For example,
theres nothing to stop you from including the statement cin >> vectorA[723] in your program.
The program will compile and will execute, but the consequences of such assignments on the
execution of the program are unpredictable and very dicult to detect and debug. It is left to
the programmer to check that the array is big enough to hold all the values and that undened
elements are not read or assigned. Assigning array values outside the permitted range is probably
one of the most common programming errors. An object-oriented approach to programming,
which well discuss in due course, can reduce the risk of such programming errors. There are also
debugging utilities, which can help spot memory mismanagement. Well discuss these later in the
course.
67
14.4 Passing arrays to functions
14.4.1 Function denition and prototype
To pass an array to a function, the array type and name is included in the formal parameter list
(i.e., in the function denition and prototype parameter list). The following is a function header
for a function that receives an array of real numbers.
void NormaliseData(float arrayName[], int arraySize)
14.4.2 Function call
In C++ the entire array is passed using the array name (and no square brackets). This looks
similar to pass by value but is actually a pass by reference. The actual parameter passed to the
function, the name of the array, is in fact the memory address of the rst element of the array.
The important point to note here is that (as with passing by reference) when you pass an array to
a function you will be able to access and modify the values of any of its elements. Arrays cannot
be passed by value.
In the following call to the NormaliseData() function, a 300 element array, marks, is passed
to the function:
NormaliseData(marks, 300);
The function can read and change the value of any of the elements of the array.
RotationMatrix.cc on page 71 is a working example.
If you need to pass only a single element of the array and you want to take advantage of the
simplicity and safety of passing by value, this can be done, for example, by having marks[2] as
an actual parameter in the call to the function. For example in the following function:
float ProcessIndividual(float mark); //Function prototype
scaledMark = ProcessIndividual(marks[2]); //Function call
the call passes the value of marks[2], which it stores as a local variable (mark). Changes to the
value of the local variable will not aect the value in the calling function.
Another way to enforce safe passing of an array that should not be modied by a function is
to declare the array const from the point of view of the function, as illustrated by this function:
void print1( const float array[] , int N ) {
for ( int n = 0 ; n < N ; n ++ ) {
cout << array[n] << " " ;
}
cout << endl;
}
14.5 Character arrays
A common use of the one-dimensional array structure is to create character strings. A character
string is an array of type char that is terminated by the null terminator character, \0. The
symbol \0 looks like two characters but represents one. It is called an escape sequence.
A character array can be initialised on declaration by enclosing the characters in double quotes.
The null character will be automatically appended.
68
// CharacterArray.cc
// Initialisation of a character array and passing to functions
#include <iostream>
using namespace std;
void PrintExtensionNumber(char phoneNumber[]);
int main()
{
char phone[11];
char prompt[] = "Enter telephone number: ";
// Get phone number
cout << prompt ;
cin >> phone ;
// If first two digits are 3 then it is a university number.
if( phone[0]==3 && phone[1]==3)
{
cout << "University extension ";
PrintExtensionNumber(phone);
}
else
{
cout << "Dial 9-" << phone[0];
PrintExtensionNumber(phone);
}
return 0;
}
// Function to print out a phone number, ignoring the first digit.
void PrintExtensionNumber(char phoneNumber[])
{
for(int i=1; phoneNumber[i] != \0; i++)
{
cout << phoneNumber[i];
}
cout << endl;
}
14.6 Multi-dimensional arrays
The arrays that we have looked at so far are all one-dimensional arrays, however, C++ allows
multidimensional arrays. For example to declare a two-dimensional array to represent the data of
a 3 by 4 matrix called myMatrix we could use the following statement and syntax:
69
float myMatrix[3][4];
You may think of the element with indices i and j, myMatrix[i][j], as the matrix element
in the i row and j column, but remember that array indices always start from 0.
The following program illustrates the passing of arrays to and from functions. The function
ComputeMatrix() assigns values to the elements of a 2 by 2 rotation matrix. The actual parame-
ters passed are the name of the rotation matrix (i.e., memory address of the rst element) and an
expression to determine the rotation angle in radians. The element matrix[0][1] is the element
of the rst row and second column of the matrix.
The function RotateCoordinates() computes the coordinates of a point after transformation
by the following equation:
_
x
_
=
_
cos sin
sin cos
_ _
x
y
_
It is passed the name of the matrix and the name of the initial position vector and transformed
position vector.
70
// RotationMatrix.cc
// Program to calculate coordinates after rotation
#include <iostream>
#include <cmath>
using namespace std;
void ComputeMatrix(float matrix[2][2], float angle);
void RotateCoordinates(float rot[2][2], float old[2], float transformed[2]);
int main()
{
float angle, point[2], transformedPoint[2];
float rotation[2][2];
// Get angle of rotation and initial position from input.
cout << "Enter magnitude of rotation in xy plane in degrees: " ;
cin >> angle;
cout << "Input x and y coordinates: " << endl;
cin >> point[0] >> point[1];
// Calculate coefficients of rotation matrix and transform point.
// The value of pi is declared in math as M_PI.
ComputeMatrix(rotation, (M_PI*angle/180.0));
RotateCoordinates(rotation, point, transformedPoint);
// Output result.
cout << "The (x,y) coordinates in the rotated system are ";
cout << transformedPoint[0] << " and " << transformedPoint[1] << endl;
return 0;
}
void ComputeMatrix(float matrix[2][2], float angle)
{
matrix[0][0] = cos(angle);
matrix[0][1] = sin(angle);
matrix[1][0] = -sin(angle);
matrix[1][1] = cos(angle);
}
void RotateCoordinates(float rot[2][2], float old[2], float transformed[2])
{
transformed[0] = (rot[0][0] * old[0]) + (rot[0][1] * old[1]);
transformed[1] = (rot[1][0] * old[0]) + (rot[1][1] * old[1]);
}
71
14.7 Structures
Arrays are examples of data structures in which all the elements must be of the same type. C++
allows the user to dene more general data structures, using the keyword struct to dene a
collection of related variables of any type, called a structure. For example:
struct StudentType{
char name[100];
int age;
int entryYear;
float marks[5];
char college[20];
};
denes a new data type called StudentType, which is made up of ve elds or data members: two
integers, an array of oating point numbers and two character arrays. The body of the structure
denition is delineated by braces and must end with a semicolon. The denition is placed at the
top of a program le, between include directives and the function prototypes.
Once a structure has been dened, the structure name can be used to declare objects of that
type. This is analogous to declaring simple variables.
StudentType person;
StudentType firstYear[400];
declares the variable person and the one-dimensional array, firstYear[400] to be of type
StudentType.
Data members of a structure are accessed and assigned values by specifying the eld (data
member) name using the dot operator, for example:
person.age = 19;
firstYear[205].entryYear = 1999;
Structures have the advantage that, by collecting related items together, they can be manipu-
lated as single items. For example whole structures can be copied using an assignment statement
(unlike arrays):
firstYear[24] = person;
and manipulated eciently with repetition control statements:
for(int i=0; i< 400; i++)
{
firstYear[i].entryYear = 1999;
}
14.8 Enumerated constants
There are many examples of data that are not inherently numeric. For example, the days of the
week, months of the year, colours. We can refer to such data types by dening symbolic constants
and using these symbolic constants in expressions in the program. For example:
const int Mon=0, Tue=1, Wed=2, Thu=3, Fri=4, Sat=5, Sun=6;
72
C++ provides a more convenient way for the user to dene a new data type. The C++ enumer-
ation statement:
enum Days {Thu, Fri, Sat, Sun, Mon, Tue, Wed};
creates a new variable type with legal values Thu, Fri, . . . , Wed, which are in fact symbolic
constants for 0, 1, . . . , 6. The enumeration is simply assigning an integer to a symbolic constant.
The denition makes it convenient to work with days of the week.
Variables can be declared as having the user-dened type and this will ensure that they are
only assigned one of the legal values. The following statement declares the variable day to have
the user-dened type, Days.
Days day;
15 Reading and writing to les
Storage of data in variables and arrays is temporary. Files are used for permanent retention of
large amounts of data. We will now show how C++ programs can process data from les. To
perform le processing in C++, the header le <fstream> must be included. The latter includes
the denitions of ifstream and ofstream classes (special structure denitions). These are used
for input from a le and output to a le.
The following command opens the le called, name.dat, and reads in data, which it stores
sequentially in variables a and b:
ifstream fin;
fin.open("name.dat");
fin >> a >> b;
The object called fin is declared to be of type (class) ifstream. The member function called
open() is used to associate the le name, name.dat, with the object name, fin.
In a similar way we can write data (in this example, the values of an array) to a le called
output.dat with:
ofstream fout;
fout.open("output.dat");
for(int i=0; i<N; i++)
{
fout << array[i] << endl;
}
fin and fout are ifstream and ofstream objects respectively. Note that fin and fout are
arbitrary names assigned by the programmer. Using fin and fout highlights the similarity with
the simple input and output statements of section 7, which use the input and output stream
objects cin and cout respectively. The syntax of the input and output statements is identical.
The only dierence is that care must be taken to ensure the les are opened and closed correctly,
i.e., that the le exists and is readable or writable. This can be checked by testing the value of
fin.good() or fout.good(). These will have the values true if the les are opened correctly.
The program on the next page reports an error if the le name specied was not found or
could not be opened and prompts the user for another le name. After nishing reading from and
writing to les, the les must be closed using:
73
fin.close();
fout.close();
and the ifstream and ofstream objects fin and fout can be re-assigned.
// OpenFile.cc
// Program to read data from a file. File name is input by user.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char fileName[80];
// Get filename from keyboard input
cout << "Enter input file name: ";
cin >> fileName;
// Declare fin to be of type (class) ifstream
// Associate file name with fin
ifstream fin;
fin.open(fileName);
// Prompt for new file name if not able to open
while(fin.good() == false)
{
cout << "Unable to open file. Enter a new name: ";
cin >> fileName;
// once bad, the file stream will stay bad unless cleared
fin.clear();
fin.open(fileName);
}
return 0;
}
Health Warning. The following section is included be-
cause its good to see examples of how blocks of memory
can be allocated. However, if you nd yourself needing to
use arrays (or array-like things) with sizes determined at
run time in C++ you almost certainly would be better-
o using one of the Standard Template Library Container
Classes such as the the std::vector. Sadly, these are
not covered in this course, though they feature in the Part
II course.
74
16 Direct allocation of arrays with new
Above, we declared arrays of xed size like this
float position[3];
int count[100];
for(int i=0; i< 100; i++)
{
count[i] = 0;
}
This xed-size approach is an inexible way of doing things, and it hard-wires numbers like 3
and 100 into your code, whereas such numbers should almost always be parameters. It would
be more elegant to replace the 100 above by a name (such as N), and use that name everywhere,
and x the value of N just once at the start of the program. It can sometimes be useful to allow N
to be set interactively or on the command-line of the program in the way that RandDemo6.cc,
for example, could optionally set the number of points N (page 34 of tutorial 1). The ugly way of
doing arrays does not allow the creation of arrays of size controlled by a variable.
In C++ we can create variable-sized arrays on the y while a program is running. We use a
special command new to allocate the memory for an array, and a complementary command delete
to free up the memory again when we dont need it any more.
The example program NewDelete.cc illustrates how to use new and delete, and how to pass
an array to a function.
// NewDelete.cc
#include <iostream>
using namespace std;
void show( double *a , int N ){
for( int n=0; n<N; n++ )
cout << "a["<<n<<"]=\t"
<< a[n]
<< endl ;
}
int main()
{
double *a ;
// This creates a pointer but doesnt allocate any memory for the array
int N = 20 ;
a = new double[N] ; // allocates memory for a[0]..a[N-1]
for( int n=0; n<N; n++ )
a[n] = n*n ;
show( a , N ) ;
delete [] a ; // frees the memory
}
In C++, array indices by default run from zero. But if you want an array that runs from, say, 1
to N, then you can do this by creating an array a[0]. . . a[N-1] of the right size, then osetting the
75
pointer by 1 (using b=a-1), so that b[1]. . . b[N] points to the same locations as a[0]. . . a[N-1].
This convenient osetting is demonstrated in the next example.
We can also allocate memory on the y for more complex objects such as matrices. A good
way to think of an MN matrix with typical entry q[m][n] is that it consists of M vectors, each
of length N. We can allocate memory for a pointer (q) to an array of pointers (q[1]. . . q[M]).
Each of the pointers q[1]. . . q[M] is just like the pointer a in the previous example, pointing to
its own personal chunk of memory of size N. This way of handling matrices is demonstrated in
several examples on the website.
You can pass arrays to functions only by reference, not by value.
17 Modularizing
In section 11, we introduced the idea of chopping a program into small chunks called functions.
Its good style to put each conceptual bit of the program in its own function. Try to avoid writing
the same piece of code more than once.
In accordance with this principle of writing everything once only, its also a good idea to put
any function that you might want to use again into a le that other programs can make use of.
Theres a couple of ways to split programs over multiple les.
1. The simple way with #include. If you put the directive #include "blah.cc" on one line of
a C++ program then the compiler will behave exactly as if the contents of the le blah.cc
were there, in your le, at that point. In this way you need to compile only one le the
other les get read in appropriately.
2. The professional way with linking. Alternatively, you can split the program into multiple
les each of which is compiled separately. In this approach, the compiler needs to be run
several times, once for each separate le, and then a nal time to link the compiled les
together. Compiling each individual .cc le creates a corresponding .o le. Linking takes
all the .o les and combines them into a single executable. Just one of the .cc les should
contain a denition of the main function, which is where the executable starts.
When compiling an individual le, the compiler doesnt need to know anything about the
functions in the other les, except for the syntax of any functions that get used in the current
le. That syntax is conveyed to the compiler by function declarations. The recommended
technique to handle these function declarations is to ensure that all functions in the le
blah.cc are declared in another le called blah.h, which is #included by blah.cc and by
any other les that wish to use blah.ccs functions.
This linking technique is illustrated by the four les that follow. The main program is in
package1.cc. This program uses utility functions for memory allocation and array printing,
located in the le tinyutils.cc. Both package1.cc and tinyutils.cc include the header
le tinyutils.h. And nally, to keep track of what needs compiling when, it is essential to
use a Makefile. The Makele must contain an explicit statement that package1 depends on
package1.o and tinyutils.o, and (on the following line, which must start with a single tab
character) an explicit instruction of how to link them together.
76
// tinyutils.h
// declares the functions defined in tinyutils.cc
using namespace std;
// memory management
double *dvector ( int low, int high ) ;
void freedvector ( double* a , int low ) ;
// printing
void printVector( double *b , int lo , int hi , int style=1 ) ;
// Note that any default parameter values (such as style=1)
// must be specified in the declaration.
// maths
double square( double a ) ;
Note that in the makele below, the indentation must be done with a tab character,(not with
spaces and not ignored) or the makele will not work.
# Makefile for package1 and package2
CFLAGS = -ansi -g -Wall
LIBS = -l stdc++ -lm
CXX = g++
# These lines define what package1 depends on, and how to make it
package1: package1.o tinyutils.o
$(CXX) $(CFLAGS) $(LIBS) package1.o tinyutils.o -o package1
package2: package2.o tinyutils2.o
$(CXX) $(CFLAGS) $(LIBS) package2.o tinyutils2.o -o package2
%.o: %.cc
$(CXX) $(CFLAGS) $< -c -o $@
%: %.cc Makefile
$(CXX) $(CFLAGS) $(LIBS) $< -o $@
77
// package1.cc
// demonstrates how to use functions
// defined in a separately-compiled file (tinyutils.cc)
#include <iostream>
using namespace std;
// Both this file and tinyutils.cc include the
// function declarations from a single header file:
#include "tinyutils.h"
// In this example, we use functions dvector,
// square, printVector, and freedvector, all defined in
// tinyutils.cc
int main()
{
double *b , *a ;
int N = 20 ;
// allocate the space for b[1]..b[N]
b = dvector( 1 , N ) ;
a = dvector( 1 , N ) ;
for ( int n = 1 ; n <= N ; n ++ )
a[n] = static_cast<double>(n) ;
for ( int m = 1 ; m <= N ; m ++ )
b[m] = square( a[m] ) ;
printVector( b , 1 , N ) ;
// free the memory
freedvector( b , 1 ) ;
freedvector( a , 1 ) ;
return 0;
}
78
// tinyutils.cc
// provides functions for double vectors allocation and clean-up
#include <iostream>
using namespace std;
#include "tinyutils.h"
// allocates memory for an array of doubles, say b[low]..b[high]
// example usage: b = dvector( 1 , N ) ;
double *dvector ( int low, int high ) {
int N = high-low+1 ;
double *a ;
if ( N <= 0 ) {
cerr << "Illegal range in dvector: "
<< low << ", " << high << endl ;
return 0 ; // returns zero on failure.
}
a = new double[N] ; // allocates memory for a[0]..a[N-1]
if(!a) {
cerr << "Memory allocation failed\n" ;
return 0 ; // returns zero on failure.
}
return (a-low) ; // offset the pointer by low.
} // the user uses b[low]..b[high]
void freedvector ( double *b , int low ) {
delete [] &(b[low]) ; // The [] indicate that whats
} // being freed is an array
// Note that default parameter values (such as style=0) have already
// been specified in the function declaration in tinyutils.h.
void printVector( double * b , int lo , int hi , int style ) {
// style 1 means "all on one line"; style 0 means "in one column"
for ( int n = lo ; n <= hi ; n ++ ) {
cout << b[n] ;
if(style) {
if ( n == hi ) cout << endl;
else cout << "\t" ;
} else {
cout << endl;
}
}
}
double square( double x ) {
return x*x ;
}
When we type make package1, the following things happen.
79
1. make looks at the Makele and learns that package1 depends on package1.o and tinyutils.o.
2. If package1.o needs to be made, make invokes
g++ -ansi -pedantic -g -Wall package1.cc -c -o package1.o
At this stage, the compiler compiles just the functions that are dened in package1.cc.
3. Similarly for tinyutils.o, make invokes
g++ -ansi -pedantic -g -Wall tinyutils.cc -c -o tinyutils.o
4. For the nal linking step, make invokes
g++ -ansi -pedantic -g -Wall -l stdc++ -lm package1.o tinyutils.o -o package1
yielding the executable package1. Its at this stage that the compiler will complain if any
functions have been declared but not dened.
18 Structures and packages
We described, last term, how to use structures. Structures are a great way to organize things that
belong together, and that should never really be separated from each other, such as a vector and
its index range. By putting such things together into a single object, we can make code briefer
(because we just refer to the one object, rather than its parts), and less buggy. The next example
shows how to rewrite the previous examples vector-creation and vector-printing using a structure
that contains the vectors pointer and its index range. The structure is dened in the header
le. Why is it a good idea to use this structure? For this toy example, it doesnt seem like a big
deal, but what you can notice is that function-calls that do things with the vector, once its been
created (such as printDvector(b)), are simpler and briefer, because we dont need to send along
the baggage (low, high) that is required in the un-structured approach. The structure contains
this baggage, so when we pass the pointer to the structure to other functions, those functions get
access to exactly the baggage they need. The only down-side of this structured approach is that
when we want to access the contents of the vector, we have to get the pointer to the vector out of
the structure, so what used to be a[n] in the old approach (where a was the pointer to the array)
becomes a.v[n] in the new approach (where a is the structure).
80
// package2.cc
// demonstrates how to use structures and functions
// defined in a separately-compiled file (tinyutils2.cc).
// The structure Dvector is defined in tinyutils2.h
#include <iostream>
using namespace std;
// Both this file and tinyutils2.cc include the
// function declarations from a single header file:
#include "tinyutils2.h"
int main()
{
Dvector a , b ;
int N = 20 ;
// allocate the space for b.v[1]..b.v[N]
allocate( b , 1 , N ) ;
allocate( a , 1 , N ) ;
for ( int n = 1 ; n <= N ; n ++ )
a.v[n] = static_cast<double>(n) ;
for ( int m = 1 ; m <= N ; m ++ )
b.v[m] = square( a.v[m] ) ;
printDvector( b ) ;
// free the memory
freeDvector( b ) ;
freeDvector( a ) ;
return 0;
}
81
// tinyutils2.h
// declares the structures and functions defined in tinyutils2.cc
using namespace std;
struct Dvector {
double *v ; // the vector itself
int low;
int high;
} ; // dont forget the semicolon in the structure definition
// memory management
int allocate( Dvector &a , int low, int high ) ;
void freeDvector ( Dvector &a );
// printing
void printDvector( Dvector &b , int style=0 ) ;
// Default parameter values (such as style=0)
// must be specified in the declaration.
// maths
double square( double a ) ;
82
// tinyutils2.cc
// provides functions for double vectors allocation and clean-up
#include <iostream>
using namespace std;
#include "tinyutils2.h"
// allocates memory for an array of doubles. Example: allocate( b, 1 , N ) ;
int allocate ( Dvector &a , int low, int high ) {
a.low = low ; a.high = high ;
int N = high-low+1 ;
if ( N <= 0 ) {
cerr << "Illegal range in dvector: "
<< low << ", " << high << endl ;
return 0 ; // returns zero if failure.
}
a.v = new double[N] ; // allocates memory for a[0]..a[N-1]
if(!a.v) {
cerr << "Memory allocation failed\n" ;
return 0 ;
} else {
a.v -= low ; // offset the pointer by low.
return 1 ;
}
}
void freeDvector ( Dvector &b ) {
delete [] &(b.v[b.low]) ;
b.high = b.low - 1 ;
}
// Note that default parameter values (such as style=0) have already
// been specified in the function declaration in tinyutils2.h.
void printDvector( Dvector &b , int style ) {
// style 1 means "all on one line"; style 0 means "in one column"
for ( int n = b.low ; n <= b.high ; n ++ ) {
cout << b.v[n] ;
if(style) {
if ( n == b.high ) cout << endl;
else cout << "\t" ;
} else {
cout << endl;
}
}
}
double square( double x ) {
return x*x ;
}
83
19 Formatted output
Weve mainly printed out numbers using cout with commands like
cout << myint << " " << mydouble << endl ;
What if you dont like the way cout makes your numbers look, however? Too many decimal
places? Too few? Well, cout can be bossed around and can be told to serve up numbers with
dierent numbers of decimal places. You can nd out more about cout by looking in a manual
online or on paper.
Here well describe another way to control output formatting, using the old-fashioned C func-
tion, printf (which means print, formatted). Its probably worth learning a bit about printf
because its syntax is used in quite a few languages.
The commands
int age = 84; printf( "his age is %d years" , age ) ;
will print the string his age is 84 years. The command
printf( "%d %d\n" , i , j ) ;
causes the integers i and j to be printed, separated by a single space, and followed by a newline
(just like cout << i << " " << j << endl ;). The command
printf( "%3d %-3d\n" , i , j ) ;
causes the same numbers to be printed out but encourages i to take up 3 columns, and to be
right-aligned within those 3 columns; and encourages j to take up 3 columns and to be left-aligned.
Text and numbers can be mixed up. For example,
printf( "from %3d to %-3d\n" , i , j ) ;
might be rendered as
from 123 to 789
Notice how you specify the format of the whole string rst, then the missing bits, each of which
was indicated in the format string by a specer, %something. The format specier for a single
character is %c; for a string of characters, %s. The special character \n is a newline; \t is a tab;
\" gives a double quote; \\ gives a single backslash. The command
printf( "%f %e %g \n" , x , y , z ) ;
prints the oating point numbers x, y, and z as follows: x is printed as a oating point number
with a default number of digits (six) shown after the decimal point; y is printed in scientic
(exponential) notation; z is printed using whichever makes more sense, xed oating point or
scientic notation. The program Printf.cc on the website illustrates more examples. I usually
use the format
printf( "%12.6g %12.6g %12.6g" , x , y , z ) ;
to print my real numbers this format gives each of them 12 columns, and shows 6 digits of
precision.
84
20 Notes concerning the remaining SESSIONS 5, 6 and 7.
The aim of the remaining SESSIONS will be not only to learn
more about C++ but also to see how programming can help you
understand physics better.
This nal two assessed tasks are harder than last terms.
Its essential to prepare before each weeks programming exercises.
Read this manual and sketch out a plan of what you are going to
do before sitting down at the computer.
The exercises involve physics, so you will need to prepare both
physics thoughts and computing thoughts. Please allow two
hours preparation time per week.
Remember that you can use the linux PWF system remotely. If you have a personal computer,
set up a C++-programming environment for yourself all the software used in this course is free
software, available for any computer platform.
85
Part IB Computing Course 2011
PRACTICAL SESSION 5 : PLANET
21 Instructions
21.1 Objectives
Physics objectives: to better understand Newtons laws, circular motion, angular momentum,
planets orbits, Rutherford scattering, and questions about spacemen throwing tools while
oating near space shuttles.
Computing objectives: structures, arrays, using gnuplot; simulation methods for dierential
equations (Euler, Leapfrog).
You are encouraged to work in pairs, with the weaker programmer doing all the typing.
21.2 Task
Simulate Newtons laws for a small planet moving near a massive sun. For ease of plotting, assume
the planet and its velocity both lie in a two-dimensional plane. Put the sun at the origin (0, 0) and
let the planet have mass m and inital location x
(0)
= (x
1
, x
2
) and initial velocity v
(0)
= (v
1
, v
2
).
The equations of motion are:
dx
dt
= v(t)
m
dv
dt
= f(x, t),
(1)
where, for a standard inverse-square law (gravity or electrodynamics) the force f is:
f(x, t) = A
x
_
_
i
x
2
i
_
3
, (2)
with A = GMm for gravitation, and A = Qq/(4
0
) for electrodynamics with two charges Q
and q.
Try to write your programs in such a way that itll be easy to switch the force law from
inverse-square to other force laws. For example, Hookes law says:
f(x, t) = kx. (3)
How should we simulate Newtons laws (1) on a computer? One simple method called Eulers
method makes small, simultaneous steps in x and v. We repeat lots of times the following block:
Eulers method
1: Find f = f(x, t)
2: Increment x by t v
3: Increment v by t
1
m
f
4: Increment t by t
86
We might hope that, for suciently small t, the resulting state sequence (x, v) in the computer
would be close to the true solution of the dierential equations.
Eulers method is not the only way to approximate the equations of motion.
An equally simple algorithm can be obtained by reordering the updates. In the following block,
the updates of f and x have been exchanged, so the force is evaluated at the new location, rather
than the old.
A: Increment x by t v
B: Find f = f(x, t)
3: Increment v by t
1
m
f
4: Increment t by t
Its not at all obvious that this minor change should make much dierence, but often it does.
This second method, in which position and velocity are updated alternately, is called the Leapfrog
method. Here is a precise statement of the Leapfrog method.
Leapfrog method
Repeat
{
Increment x by
1
2
t v
Increment t by
1
2
t
Find f = f(x, t)
Increment v by t
1
m
f
Increment x by
1
2
t v
Increment t by
1
2
t
}
In this version, we make a half-step of x, a full-step of v, and a half-step of x. Since the end of
every iteration except the last is followed by the beginning of the next iteration, this algorithm
with its half-steps is identical to the previous version, except at the rst and last iterations.
When simulating a system like this, there are some obvious quantities you should look at: the
angular momentum, the kinetic energy, the potential energy, and the total energy.
Techniques to use:
1. Represent the vectors x, v, and f using arrays. Make sure you look at some simple examples
of arrays before using them for planets.
2. Put all the variables and arrays associated with a single object (such as a planet) in a
structure. Make sure you look at some simple examples of structures.
21.3 Ideas for what to do
This is a self-directed and self-assessed course, and Id like you to choose a planet-simulating
activity that interests you. Here are some suggestions. You dont have to do all of these.
You can also invent your own. The more you do, the more educational itll be. But do take
your pick, and feel free to steal working code (e.g. from the course website) if youd prefer to focus
your energy on experimenting with working code, rather than writing and debugging your own.
1. Write code that implements Eulers method and the Leapfrog method. Get it going for
one initial condition, such as x
(0)
= (1.5, 2), v
(0)
= (0.4, 0). Before running your program,
predict the correct motion, roughly. Compare the two methods, using gnuplot to look at the
87
-3
-2
-1
0
1
2
3
-3 -2 -1 0 1 2 3
Figure 1: The initial condition x
(0)
= (1.5, 2), v
(0)
= (0.4, 0).
resulting trajectories, the energies, and the angular momenta. (If youd like more detailed
guidance through a possible approach to this task, see the appendix on p. 98. A worked
solution for this rst part is also available.)
2. Once you have a trustworthy simulation: take a collection of similar initial conditions, all
having the same initial position and initial energy but diering in the direction of the initial
velocity. What happens? Show all the evolving trajectories in a single movie.
3. Or take initial conditions that dier slightly in their initial position or velocity, such as the
spaceshuttle and the spaceman who is 100 yards from the spaceshuttle, both orbitting the
earth (in what direction does he need to nudge himself in order to get home?). Or the
spaceman and the hammer if he throws his hammer forwards, where does it end up
going? If he throws it back or sideways, where does it end up going? (Here the idea is
to simulate two planets orbitting a single sun; to get the spaceman analogy, think of the
spaceman and his shuttle being like the two planets, and the earth playing the role of the
sun.)
4. Get an initial condition that leads to a perfectly circular orbit. Now perturb that initial
condition by giving a little kick of momentum in 8 dierent directions. Show all nine resulting
trajectories in a single movie. Which kicks lead to the period of the orbit changing? Which
kicks lead to the period of the orbit staying the same? Which kicks lead to orbits that come
back to the place where the kick occurred? If an object is in an elliptical orbit, what kicks
do you give it in order to make the orbit larger and circular? What kicks do you give it to
make the orbit smaller and circular? Whats the best time, in an elliptical orbit, to give the
particle a kick so as to get the particle onto an orbit that never comes back, assuming we
want the momentum in the kick to be as small as possible?
5. Take initial conditions coming in from a long way away, particles travelling along equally-
spaced parallel lines. What happens? (The distance of the initial line from the sun is called
the impact parameter of the initial condition.)
6. People who criticise Eulers method often recommend the RungeKutta method. Find out
what RungeKutta is (Google knows), implement it, and compare with the Leapfrog method.
Choose a big enough step-size t so that you can see a dierence between the methods.
Given equal numbers of computational operations, does RungeKutta or Leapfrog do a
88
better job of making an accurate trajectory? For very long runs, and again assuming equal
numbers of computational operations, does RungeKutta or Leapfrog do a better job of
energy conservation? Of angular momentum conservation?
21.4 What to hand in
This SESSION has a slightly dierent than SESSIONS 1 to 4 as the emphasis is now on using
computing to help you learn about physics, rather than just learning to program. This means
that there is greater importance attached to the Brief Description part of the
submission than in the earlier sessions, and consequently it will be longer than in the
earlier sessions, and will contain a greater discussion of physics directed goals than
of the computing ones.
You will be expected to use the brief description part of the web-based submission form to
explain not only the technical/computational challenges which you faced, but also to devote a
greater than normal time to explaining the physics goals which you set yourself (perhaps based
on the suggestions of section 21.3) and what use of your program helped you learn about them.
This additional part of the Brief Description is the part you must engage with if you are to
gain the extra credit for this section.
As usual, you will gain credit for uploading the programs you used to solve the problems, but
here it is possible (though not required) that you may have used gnuplot, or other tools, and may
decide to hand in evidence of them too. The choice is yours. In all cases, explain what your
submissions allowed you to do or to test.
As the description will be longer than normal, and to avoid having to curse your browser if
you hit the back button inadvertently, you are reminded to create your brief description in a
separate README le (saving as you compose) before pasting it into the submission form as the
nal step. The form itself is crude and will not remember text if you happen to hit the back
button or visit another page seconds before pressing submit !
END OF SESSION 5 : PLANET
89
Part IB Computing Course 2011
PRACTICAL SESSION 6 : BONKERS
22 Instructions
22.1 Objectives
Physics objectives: to better understand collisions, conservation laws, and statistical physics,
especially equipartition, properties of ideal gases, the concept of temperature, and the Boltz-
mann distribution; also the way in which microscopic physics leads to macroscopic phenom-
ena; what happens when a piston compresses an ideal gas; adiabatic expansion; uctuations
and dissipation, equilibration of systems with dierent temperatures.
Computing objectives: structures, arrays, using gnuplot; memory allocation.
You are encouraged to work in pairs, with the weaker programmer doing all the typing.
22.2 Task
Were going to simulate hard spheres colliding with each other elastically in a box. An incredible
range of interesting physics phenomena can be studied in this way.
The heart of this computing exercise is going to be a single function lets call it collide
which receives two particles with masses m
1
and m
2
and velocities u
1
and u
2
, and returns the new
velocities v
1
and v
2
of the two particles after an elastic collision between the two.
You could start by writing a function that implements this elastic collision. Check your function
with special cases that youve solved by hand, and by putting in a range of initial conditions and
evaluating whether total momentum and total energy are indeed conserved as they should be.
An elegant approach to this programming task uses a structure to represent each particle
something like this, for a particle moving in one dimension:
struct particle {
double x ; // position
double p ; // momentum
double im ; // inverse mass
double v ; // velocity
double T ; // kinetic energy
double a ; // radius of particle
} ; // Note the definition of a structure ends with a semicolon
At this stage its not crucial, but at some point I recommend making sure all references to the
particles mass use the inverse mass, rather than the mass this allows you to treat the walls of
the box as standard particles that just happen to have innite mass (that is, inverse-mass zero).
90
Once you have dened a struct like particle, you may dene an array of particles in just
the same way that you dene arrays of other objects like ints or doubles. For example
a = new particle[N] ;
22.3 Ideas for what to do
Theres a lot of choice. This is a self-directed and self-assessed course, and Id like you to choose
a bonking-simulating activity that interests you.
Here are some suggestions. You dont have to do all of these. You can also invent your
own. The more you do, the more educational itll be. But do take your pick, and feel free to steal
working code (e.g. from the course website) if youd prefer to focus your energy on experimenting
with working code, rather than writing and debugging your own.
1. Write code that uses a one-dimensional collide function to simulate the motion of N parti-
cles in a one-dimensional box. Each particle can collide only with its immediate neighbours;
each of the two end particles can collide with one wall too. To simulate the dynamics, you
must identify the times at which collisions occur, and (assuming you want to make a realistic
movie for showing in gnuplot) spit out the state of the simulation at equally spaced times. A
suggested strategy is to take the current state and gure out which pair of adjacent particles
will collide next. Then advance the simulation exactly to the moment of that next collision
(stopping if appropriate at intermediate times along the way, so as to spit out the required
states for the movie, equally spaced in time). Collisions should be handled by passing the
pair of particles to the collide function. Motion in between collisions is simple (since there
are no forces) and it should be handled by another function, leapForward, say. Printing out
of the state at certain times of interest should be handled by another function, showState,
say. (A worked solution for this rst part is available on the course website.)
[A possible diculty with this approach of computing all collisions that occur is that it
is conceivable that the true number of collisions in a nite time might be very large, a
phenomenon known as chattering. You can get the idea of chattering by imagining quickly
squashing a moving ping-pong ball between a table-tennis bat and a table.]
2. Testing: Put just two particles in a box, with equal masses. Check that the dynamics
are right. Make the two masses unequal. Make a scatter-plot of the positions of the two
particles. Make a scatter-plot of the velocities of the two particles. Use more masses. Check
that kinetic energy is conserved.
3. Put quite a few unequal masses in the box (say, 10 masses, with a variety of masses spanning a
range of a factor of 4 in magnitude), run the simulation for a long time, and make histograms
of the velocities of two of the particles whose masses are in the ratio 4:1. What do you nd?
Make histograms of the positions of the particles. If you make some of the particles really
heavy compared to their neighbours, what happens to the histogram of the positions of the
neighbours? For example, make all the particles except for the two end particles be much
larger; or make half the particles (those on the left hand side) heavy, and the other half
light. (In all simulations make sure no two adjacent particles have identical masses.)
4. What happens if the right-hand wall (with innite mass) is moved at constant speed towards
or away from the other wall?
Ye have heard it said that, under some circumstances, pV
= constant. What is for a
one-dimensional ideal gas? How should the total energy vary with V under these conditions?
91
5. Set up N
1
light masses to the left of a single big heavy mass, and N
2
more light masses
to the right of the heavy mass. Call the heavy mass a piston, if you like, and think of it
as separating two ideal gases from each other. The light masses dont need to be identical
to each other. An example set of masses for N
1
= N
2
= 5 could be (1.1, 1.2, 1.1, 1.3,
1.1, 100.0, 4.1, 4.2, 4.1, 4.8, 4.4) where the 100-mass is the piston. Give randomly chosen
velocities to the particles. What should happen? How long does it take for equilibrium
to be reached? Give an enormous velocity to the piston and small velocities to the other
particles. What should happen? How long does it take for equilibrium to be reached? Can
you get the piston to oscillate roughly sinusoidally (before equilibrium is reached)? What
is the frequency of such oscillations? Predict the frequency using the theory of adiabatic
expansion/compression of gases.
0
1
2
3
4
5
0 1 2 3
t
i
m
e
position
w
a
l
l
m
a
s
s
=
3
m
a
s
s
=
1
w
a
l
l
The rst six collisions
between two particles of
masses 3 and 1 and two
walls.
22.4 What to hand in
This SESSION has a slightly dierent than SESSIONS 1 to 4 as the emphasis is now on using
computing to help you learn about physics, rather than just learning to program. This means
that there is greater importance attached to the Brief Description part of the
submission than in the earlier sessions, and consequently it will be longer than in the
earlier sessions, and will contain a greater discussion of physics directed goals than
of the computing ones.
You will be expected to use the brief description part of the web-based submission form to
explain not only the technical/computational challenges which you faced, but also to devote a
greater than normal time to explaining the physics goals which you set yourself (perhaps based
on the suggestions of section 22.3) and what use of your program helped you learn about them.
92
This additional part of the Brief Description is the part you must engage with if you are to
gain the extra credit for this section.
As usual, you will gain credit for uploading the programs you used to solve the problems, but
here it is possible (though not required) that you may have used gnuplot, or other tools, and may
decide to hand in evidence of them too. The choice is yours. In all cases, explain what your
submissions allowed you to do or to test.
As the description will be longer than normal, and to avoid having to curse your browser if
you hit the back button inadvertently, you are reminded to create your brief description in a
separate README le (saving as you compose) before pasting it into the submission form as the
nal step. The form itself is crude and will not remember text if you happen to hit the back
button or visit another page seconds before pressing submit !
END OF SESSION 6 : BONKERS
93
Part IB Computing Course 2011
PRACTICAL SESSION 7 : RECURSION (optional!)
23 Instructions
23.1 Objectives
This is an optional extra.
Physics objectives: to better understand statistical physics by counting some interesting things.
Computing objectives: recursion.
Recursion means dening a function f in terms of the function f. For example we could dene
the factorial function f(x) by:
1. if x > 1 then return x f(x 1)
2. otherwise return 1.
A recursive function in a computer program is one that calls itself. Heres an example, following
the above denition closely.
// factorial calculator - recursive
#include <iostream>
using namespace std;
int factorial (int a)
{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}
int main ()
{
int number;
cout << "Please type a number: ";
cin >> number;
cout << number << "! = " << factorial(number) << endl;
return 0;
}
Errors in the denition of recursive functions often lead to disaster, since its all too easy to
write a function that keeps calling itself and never stops.
94
Some programmers nd recursion an elegant way to express many programming tasks. Here
is an example. The task is print all ternary strings of length L. For L = 1 the output should be
0, 1, 2.
For L = 2 the output should be
00, 01, 02, 10, 11, 12, 20, 21, 22
Here is a solution.
// allStrings.cc
// Enumerate all ternary strings by recursion
#include <iostream>
using namespace std;
void appendAllStrings( char *prefix , int remainingLength )
{
if (remainingLength == 0)
cout << prefix << endl ;
else {
int lp = strlen(prefix) ;
for ( int i = 0 ; i <= 2 ; i ++ ) { // Extend prefix by one character.
prefix[lp] = i+0 ; // By adding i to the character 0
// we get the characters 0, 1, 2
appendAllStrings( prefix , remainingLength-1 );
}
prefix[lp] = \0 ; // Remove what was added
// [ \0 is the null character ]
}
return ;
}
int main ()
{
int length;
cout << "Please type a length: ";
cin >> length;
char *prefix ;
prefix = new char[length] ; // Assume this memory is all-null
appendAllStrings( prefix , length ) ;
delete [] prefix ; // Free the memory
return 0;
}
The function strlen returns the length of the string generated so far; the line
prefix[lp] = ...
extends the string by one character. The algorithm proceeds by starting from the null string, and
extending it by all possible single characters, extending each in turn by all possible characters,
and so forth.
95
Such branching processes are the type of problem for which recursion is especially recom-
mended.
96
23.2 Recursion exercises
Solve each of these tasks using a recursive function.
1. Write a function called twos that takes a single integer as its argument and returns the
number of factors of 2 in the number. (Hint: odd numbers have no factors of 2, numbers
that are twice an odd number have one, numbers that are four times an odd have two, and
so on.) For example: twos(-12); should return 2.
2. Write a function called printWithCommas that takes a single nonnegative long integer argu-
ment and displays it with commas inserted in the conventional way. For example:
printWithCommas(12045670); displays 12,045,670.
printWithCommas(1); displays 1.
3. Interesting properties of a hard sphere gas.
A legal state of four particles in a
10 10 box.
A square box of size HH lattice-points contains one big particle and T = 3 little particles.
The big particle occupies 44 lattice points. Each little particle occupies 22 lattice points.
Particles may not overlap. All legal states of this T + 1-particle system are equiprobable.
How probable are the alternative locations of the big particle? Find the answer for H = 10
(by recursively enumerating all legal states, and keeping count). It is a good idea to spit out
the answer for smaller values of T along the way towards the answer for the biggest value
of T.
If not all locations of the big particle are equiprobable then we can describe the eect of
the little particles in terms of an eective force acting on the big particle. Such forces are
called entropic forces. Entropic forces in hard-sphere mixtures with a variety of sizes of
spheres are an area of industrial research interest.
10
END OF SESSION 7 : RECURSION (optional!)
10
Y. Mao, P. Bladon, H. N. W. Lekkerkerker, and M. E. Cates. Mol. Phys. 92, 151 (1997).
R. Dickman, P. Attard, and V. Simonian. Entropic Forces in Binary Hard-Sphere Mixtures: Theory and
Simulation, J. Chem. Phys. 107, 205213 (1997).
Entropic Attraction and Repulsion in Binary Colloids Probed with a Line Optical Tweezer J. C. Crocker, J. A.
Matteo, A. D. Dinsmore, and A. G. Yodh. Physical Review Letters, 82, 43524355 (1999).
97
Appendices
A PLANET: step by step guidance
1. Chop the problem into small pieces.
2. Dene a structure that contains the state of the planet. (See page 80 of this tutorial and
page 60 of the rst terms tutorial.) Your structure could be as simple as:
struct particle {
double x[2] ; // (x,y) coordinates
double v[2] ; // velocity
} ;
but as you continue, you will probably think of other sensible things to add to the structure.
You might nd it elegant to give a name to the dimensionality of the position space, say D.
#define D 2 // number of dimensions
struct particle {
double x[D] ; // (x,y) coordinates
double v[D] ; // velocity
} ; // Note the definition of a structure ends with a semicolon
If you then use D everywhere, it makes the meaning of your code clearer (compared with
using 2), and it makes it easier to update your simulations dimension (say from 2 to 3
dimensions).
3. Write a simple main that denes a particle, and check that it compiles and runs.
int main()
{
particle a ;
a.v[0] = 0.4;
a.v[1] = 0.0;
a.x[0] = 1.5;
a.x[1] = 2;
return 0;
}
4. Write a function showState that prints out the particles position and velocity. Call it from
main and check that your program compiles and runs correctly. Here is an example of a
function that does the right sort of thing:
98
void showState ( particle &a )
{
int i=0;
cout << "some of the state: " << a.x[i] << endl ;
}
This could be called by main using a command such as
showState( a ) ;
Notice the use of the ampersand in the function denition
void showState ( particle &a ).
This ampersand means that we are passing the particle by reference, rather than by value.
(See page 45 of last terms tutorial.)
5. Remember the tips from last term about debugging your code. (1) Use a makefile. (2)
Switch on all the compiler warnings. (3) Whenever you think that your code ought to
compile, check that it does so. (4) If you have code that compiles ok, but that doesnt
behave as expected when you run it, run it in a debugger (for example, kdbg). Even if it
seems to be running as expected, it might be a good idea to run it in a debugger. When I
use kdbg, the main things I click on are set breakpoint (right click), run, and the step
over icon.
6. Write a function that computes the squared-distance from the origin.
7. Write a function Force that computes the force acting on the particle, or the acceleration
of the particle. (Perhaps the force or acceleration should be in your structure?)
8. Write a function PositionStep that makes a change of a particles position in the direction
of its velocity. One of the arguments of this function should be the required time step size.
9. Write a function VelocityStep that makes a change of a particles velocity in the direction
of its acceleration.
10. Write a function that computes the energy (kinetic and potential) of the particle.
11. Write a function that computes the angular momentum about the origin.
12. Write a Leapfrog simulator with a loop that calls the above functions appropriately.
13. Write the simulated trajectory to a le using a function like showState. To plot the trajec-
tory from a le whose columns are
time, x
1
, x
2
, v
1
, v
2
,
the following gnuplot commands may be useful.
99
set size ratio -1 ; ## this makes units on the x and y axes have equal size
plot tmp u 2:3 w l, tmp every 10 u 2:3:4:5 w vector
## this plots (x1,x2) with lines, and plots every 10th state using a vector
## of length (v1,v2) based at the point (x1,x2)
gnuplots plot command is very versatile. The website shows how you can make a gnuplot
animation using a single data le containing a trajectory.
14. Be aware of the size of the les you are writing. If you give gnuplot a le of more than 1
megabyte, you should expect it to be sluggish. Maybe it would be a good idea to reduce
the amount of information written to le. You may be able to get better performance by
using the local lesystem of the machine at which you are sitting. You can write anything
you want into the folder /tmp. For example,
ls > /tmp/mylist
The /tmp folder is a good place to put anything large and anything that you want to access
frequently or quickly. But dont leave anything important in /tmp after you log out, the
/tmp folder may be cleaned up.
100
B An introduction to object-oriented programming and
classes
One of the most important dierences between the C++ programming language and some other
programming languages is the emphasis on the representation of data using programmer or user-
dened data types. In C++ an extension to the denition of structures allows the user to include
both data members (as above) and member functions which are allowed to process the data. The
encapsulation of data and functions into packages called objects of user-dened types called classes
is a key part of object-oriented programming.
In its simplest form, a class is like a structure that includes the denition of functions (member
functions or class methods) that are allowed to process the data. See the simple example below.
1. Classes and Objects
The class (e.g. Date in the example) can be considered as a specication while the actual
item (e.g. today) is an instance of a class and is called an object. Declaring an object is
very similar to declaring a variable:
class-name object-name ;
2. Accessing data members and functions
The data members and member functions of the class can be accessed by simply naming
them in conjunction with the name of the object they belong to using the dot operator.
object-name.item-name
3. Dening a class member function
The declaration and denition of class member functions is similar to those used for standard
functions: we use function prototypes to declare the functions and place the statements to
be executed in a function denition. The only dierence is that with a class member function
we must tell the compiler which class the function is a member of. This is done by including
the name of the class in the function header using a scope resolution operator represented
by ::.
return-type class-name ::function-name (parameter-list )
4. Restricting access to class members
One of three levels of access can be specied for each class member (both data and functions)
using the keywords public, private or protected followed by a colon. These refer to how
the class members may be accessed in a program.
The public members of a class may be accessed directly from anywhere in the program that
has access to an object of the class. The private members can be read or modied only by
class member functions.
101
B.0.1 A simple example
This example shows how to create a simple class and dene the classs member functions.
// SimpleClass.cc
// A program to demonstrate creation and use of a simple class for dates
#include <iostream>
using namespace std;
// Declaration of Date class
class Date {
public:
void set(int, int, int);
void print();
private:
int year;
int month;
int day;
};
int main()
{
// Create a Date object called today
Date today;
// Call Date member function set()
today.set(1,9,1999);
cout << "This program was written on ";
today.print();
cout << endl;
return 0;
}
// Date member function definitions
void Date::set(int d, int m, int y)
{
if(d>0 && d<31) day = d;
if(m>0 && m<13) month = m;
if(y>0) year =y;
}
void Date::print()
{
cout << day << "-" << month << "-" << year << endl;
}
102
C Further reading
This tutorial has introduced the basic elements of the C++ programming language. The following
references provide a comprehensive treatment and useful tips on good programming practice.
1. C++ How to Program (5th edition), Deitel, H.M and Deitel, P.J.
Prentice Hall, Englewood (NJ), 2005.
2. Code Complete: A Practical Handbook of Software Construction, McConnell, S.
Microsoft Press, Redmond (WA), 1993.
3. C++ in plain English, Brian Overland.
M&T Books, 1999.
103
D Objectives of each section
D.1 Session 1
Familiarisation with the teaching system and C++ development environment
Edit, compile and execute a working program
Become familiar with the compilers messages
D.2 Session 2
Declare and dene variables and constants
Assign values to variables and manipulate them in arithmetic expressions
Write the value of variables to the screen
Read in the value of variables from the keyboard
Write simple programs that use loops.
D.3 Session 3
Boolean expressions with relational operators
Simple control structures for selection and repetition
D.4 Session 4
Denition, declaration and calling of functions
Passing values to and returning values from functions
Math and system library functions
D.5 Session 5 : PLANET
Physics objectives: to better understand Newtons laws, circular motion, angular momentum,
planets orbits, Rutherford scattering, and questions about spacemen throwing tools while
oating near space shuttles.
Computing objectives: structures, arrays, using gnuplot; simulation methods for dierential
equations (Euler, Leapfrog).
D.6 Session 6 : BONKERS
Physics objectives: to better understand collisions, conservation laws, and statistical physics,
especially equipartition, properties of ideal gases, the concept of temperature, and the Boltz-
mann distribution; also the way in which microscopic physics leads to macroscopic phenom-
ena; what happens when a piston compresses an ideal gas; adiabatic expansion; uctuations
and dissipation, equilibration of systems with dierent temperatures.
Computing objectives: structures, arrays, using gnuplot; memory allocation.
104
D.7 Optional session 7 : RECURSION
This is an optional extra.
Physics objectives: to better understand statistical physics by counting some interesting things.
Computing objectives: recursion.
105
E Thirty useful unix commands
106
Thirty useful unix commands
This guide, based on a University computing service leaet, is intended to be as generally valid as
possible, but there are many dierent versions of Unix available within the University, so if you
nd a command option behaving dierently on your local machine you should consult the on-line
manual page for that command. Some commands have numerous options and there is not enough
space to detail them all here, so for fuller information on these commands use the relevant on-line
manual page.
The names of commands are printed in bold, and the names of objects operated on by these
commands (e.g. les, directories) are printed in italics.
Thirty useful unix commands index
1. cat - display or concatenate les
2. cd - change directory
3. chmod - change the permissions on a le or directory
4. cp - copy a le
5. date - display the current date and time
6. di - display dierences between text les
7. le - determine the type of a le
8. nd - nd les of a specied name or type
9. ftp - le transfer program
10. grep - searches les for a specied string or expression
11. gzip - compress a le
12. help - display information about bash builtin commands
13. info - read online documentation
14. kill - kill a process
15. lpr - print out a le
16. ls - list names of les in a directory
17. man - display an on-line manual page
18. mkdir - make a directory
19. more - scan through a text le page by page
20. mv - move or rename les or directories
107
21. nice - change the priority at which a job is being run
22. passwd - change your password
23. ps - list processes
24. pwd - display the name of your current directory
25. quota - disk quota and usage
26. rm - remove les or directories
27. rmdir - remove a directory
28. sort - sort and collate lines
29. ssh - secure remote login program
30. scp - securely copy les between computers
108
1. cat display or concatenate les
cat takes a copy of a le and sends it to the standard output (i.e., to be displayed on your terminal,
unless redirected elsewhere), so it is generally used either to read les, or to string together copies
of several les, writing the output to a new le.
cat ex
displays the contents of the le ex.
cat ex1 ex2 > newex
creates a new le newex containing copies of ex1 and ex2, with the contents of ex2 following the
contents of ex1.
2. cd change directory
cd is used to change from one directory to another.
cd dir1
changes directory so that dir1 is your new current directory. dir1 may be either the full pathname
of the directory, or its pathname relative to the current directory.
cd
changes directory to your home directory.
cd ..
moves to the parent directory of your current directory.
3. chmod change the permissions on a le or directory
chmod alters the permissions on les and directories using either symbolic or octal numeric codes.
The symbolic codes are given here:-
u user + to add a permission r read
g group to remove a permission w write
o other = to assign a permission explicitly x execute (for les), access (for directories)
The following examples illustrate how these codes are used.
chmod u=rw le1
sets the permissions on the le le1 to give the user read and write permission on le1. No other
permissions are altered.
chmod u+x,g+w,o-r le2
alters the permissions on the le le2 to give the user execute permission on le2, to give members
of the users group write permission on the le, and prevent any users not in this group from reading
it.
chmod u+w,go-x dir1
gives the user write permission in the directory dir1, and prevents all other users having access to
that directory (by using cd. They can still list its contents using ls.)
chmod g+s dir2
means that les and subdirectories in dir2 are created with the group-ID of the parent directory,
not that of the current process.
109
4. cp copy a le
The command cp is used to make copies of les and directories.
cp le1 le2
copies the contents of the le le1 into a new le called le2. cp cannot copy a le onto itself.
cp le3 le4 dir1
creates copies of le3 and le4 (with the same names), within the directory dir1. dir1 must already
exist for the copying to succeed.
cp -r dir2 dir3
recursively copies the directory dir2, together with its contents and subdirectories, to the directory
dir3. If dir3 does not already exist, it is created by cp, and the contents and subdirectories of
dir2 are recreated within it. If dir3 does exist, a subdirectory called dir2 is created within it,
containing a copy of all the contents of the original dir2.
5. date display the current date and time
date returns information on the current date and time in the format shown below:-
Wed Jan 9 14:35:45 GMT 2002
6. di display dierences between text les
di le1 le2 reports line-by-line dierences between the text les le1 and le2. The default out-
put will contain lines such as n1 a n2,n3 and n4,n5 c n6,n7 , (where n1 a n2,n3 means
that le2 has the extra lines n2 to n3 following the line that has the number n1 in le1, and
n4,n5 c n6,n7 means that lines n4 to n5 in le1 dier from lines n6 to n7 in le2). After each
such line, di prints the relevant lines from the text les, with < in front of each line from le1
and > in front of each line from le2.
There are several options to di, including di -i , which ignores the case of letters when
comparing lines, and di -b , which ignores all trailing blanks.
di -cn produces a listing of dierences within n lines of context, where the default is three
lines. The form of the output is dierent from that given by di, with + indicating lines that
have been added, indicating lines that have been removed, and ! indicating lines that have
been changed.
di dir1 dir2 will sort the contents of directories dir1 and dir2 by name, and then run di on
the text les that dier.
110
7. le determine the type of a le
le tests named les to determine the categories their contents belong to.
le le1
can tell if le1 is, for example, a source program, an executable program or shell script, an empty
le, a directory, or a library, but (a warning!) it does sometimes make mistakes.
8. nd nd les of a specied name or type
nd searches for les in a named directory and all its subdirectories.
nd . -name *.cc -print
searches the current directory and all its subdirectories for les ending in .cc, and writes their
names to the standard output. In some versions of Unix the names of the les will only be written
out if the -print option is used.
nd /local -name core -user user1 -print
searches the directory /local and its subdirectories for les called core belonging to the user user1
and writes their full le names to the standard output.
9. ftp le transfer program no longer recommended. See the section on scp and
ssh instead.
ftp is an interactive le transfer program. While logged on to one machine (described as the local
machine), ftp is used to logon to another machine (described as the remote machine) that les
are to be transferred to or from. As well as le transfers, it allows the inspection of directory
contents on the remote machine. There are numerous options and commands associated with ftp,
and man ftp will give details of those.
A simple example ftp session, in which the remote machine is hermes, is shown below:-
ftp hermes.cam.ac.uk
If the connection to hermes is made, it will respond with the prompt:-
Name (hermes.cam.ac.uk:user1) :
(supposing user1 is your username on your local machine). If you have the same username on
hermes, then just press Return; if it is dierent, enter your username on hermes before pressing
Return. You will then be prompted for your hermes password, which will not be echoed.
After logging in using ftp you will be in your home directory on hermes. Some Unix commands,
such as cd, mkdir, and ls, will be available. Other useful commands are:
help
lists the commands available to you while using ftp.
get remote1 local1
creates a copy on your local machine of the le remote1 from hermes. On your local machine this
new le will be called local1. If no name is specied for the le on the local machine, it will be
given the same name as the le on hermes.
send local2 remote2
copies the le local2 to the le remote2 on hermes, i.e., it is the reverse of get.
quit
111
nishes the ftp session. bye and close can also be used to do this.
Some machines oer a service called anonymous ftp, usually to allow general access to certain
archives. To use such a service, enter anonymous instead of your username when you ftp to the
machine. It is fairly standard practice for the remote machine to ask you to give your email
address as a password. Once you have logged on you will have read access in a limited set of
directories, usually within the /pub directory tree. It is good etiquette to follow the guidelines
laid down by the administrators of the remote machine, as they are being generous in allowing
such access. See leaet G72 for more detailed examples of using ftp.
WARNING! When you use ftp the communications between the machines are not encrypted.
This means that your password could be snooped when you use it make an ftp connection.
If available, the commands sftp (secure le transfer program) or scp (secure remote le copy
program) are preferable, as they provide encrypted le transfer. See later discussion of this scp.
10. grep searches les for a specied string or expression
grep searches for lines containing a specied pattern and, by default, writes them to the standard
output.
grep motif1 le1
searches the le le1 for lines containing the pattern motif1. If no le name is given, grep acts
on the standard input. grep can also be used to search a string of les, so
grep motif1 le1 le2 ... len
will search the les le1, le2, ... , len, for the pattern motif1.
grep -c motif1 le1
will give the number of lines containing motif1 instead of the lines themselves.
grep -v motif1 le1
will write out the lines of le1 that do NOT contain motif1.
11. gzip compress a le
gzip reduces the size of named les, replacing them with les of the same name extended by .gz.
The amount of space saved by compression varies.
gzip le1
results in a compressed le called le1.gz, and deletes le1.
gzip -v le2
compresses le2 and gives information, in the format shown below, on the percentage of the les
size that has been saved by compression:-
file2 : Compression 50.26% -- replaced with file2.gz
To restore les to their original state use the command gunzip. If you have a compressed
le le2.gz , then
gunzip le2
will replace le2.gz with the uncompressed le le2.
112
12. help display info about bash builtin commands
help gives access to information about builtin commands in the bash shell. Using help on its
own will give a list of the commands it has information about. help followed by the name of one
of these commands will give information about that command. help history, for example, will
give details about the bash shell history listings.
13. info read online documentation
info is a hypertext information system. Using the command info on its own will enter the info
system, and give a list of the major subjects it has information about. Use the command q to
exit info. For example, info bash will give details about the bash shell.
14. kill kill a process
To kill a process using kill requires the process id (PID). This can be found by using ps.
Suppose the PID is 3429, then
kill 3429
should kill the process. If it doesnt then sometimes adding -9 helps. . .
kill -9 3429
15. lpr print out a le
lpr is used to send the contents of a le to a printer. If the printer is a laserwriter, and the le
contains PostScript, then the PostScript will be interpreted and the results of that printed out.
lpr -Pprinter1 le1
will send the le le1 to be printed out on the printer printer1. To see the status of the job
on the printer queue use
lpq -Pprinter1
for a list of the jobs queued for printing on printer1. (This may not work for remote printers.)
113
16. ls list names of les in a directory
ls lists the contents of a directory, and can be used to obtain information on the les and directories
within it.
ls dir1
lists the names of the les and directories in the directory dir1, (excluding les whose names begin
with . ). If no directory is named, ls lists the contents of the current directory.
ls -a dir1
will list the contents of dir1, (including les whose names begin with . ).
ls -l le1
gives details of the access permissions for the le le1, its size in kbytes, and the time it was last
altered.
ls -l dir1
gives such information on the contents of the directory dir1. To obtain the information on dir1
itself, rather than its contents, use
ls -ld dir1
17. man display an on-line manual page
man displays on-line reference manual pages.
man command1
will display the manual page for command1, e.g man cp, man man.
man -k keyword
lists the manual page subjects that have keyword in their headings. This is useful if you do not
yet know the name of a command you are seeking information about, but can produce a lot of
output. To rene the output you could, for example, use man -k keyword | grep (1 to get a
list of user commands with keyword in their headings (user commands are in section 1 of the man
pages). The | means that the output of man -k is piped to (i.e., is used as the input for) grep.
man -Mpath command1
is used to change the set of directories that man searches for manual pages on command1
18. mkdir make a directory
mkdir is used to create new directories. In order to do this you must have write permission in
the parent directory of the new directory.
mkdir newdir
will make a new directory called newdir.
mkdir -p can be used to create a new directory, together with any parent directories required.
mkdir -p dir1/dir2/newdir
will create newdir and its parent directories dir1 and dir2, if these do not already exist.
114
19. more scan through a text le page by page
more displays the contents of a le on a terminal one screenful at a time.
more le1
starts by displaying the beginning of le1. It will scroll up one line every time the return key is
pressed, and one screenful every time the space bar is pressed. Type ? for details of the commands
available within more. Type q if you wish to quit more before the end of le1 is reached.
more -n le1
will cause n lines of le1 to be displayed in each screenful instead of the default (which is two lines
less than the number of lines that will t into the terminals screen).
20. mv move or rename les or directories
mv is used to change the name of les or directories, or to move them into other directories. mv
cannot move directories from one le-system to another, so, if it is necessary to do that, use cp
instead copy the whole directory using cp -r oldplace newplace then remove the old one using
rm -r oldplace.
mv name1 name2
changes the name of a le called name1 to name2.
mv dir1 dir2
changes the name of a directory called dir1 to dir2, unless dir2 already exists, in which case dir1
will be moved into dir2.
mv le1 le2 dir3
moves the les le1 and le2 into the directory dir3.
21. nice change the priority at which a job is being run
nice causes a command to be run at a lower than usual priority. nice can be particularly useful
when running a long program that could cause annoyance if it slowed down the execution of other
users commands. An example of the use of nice is
nice gzip le1
which will execute the compression of le1 at a lower priority.
If the job you are running is likely to take a signicant time, you may wish to run it in the
background, i.e., in a subshell. To do this, put an ampersand &, after the name of your command
or script. For instance,
rm -r mydir &
is a background job that will remove the directory mydir and all its contents.
The command jobs gives details of the status of background processes, and the command fg can
be used to bring such a process into the foreground.
22. passwd change your password
Use passwd when you wish to change your password. You will be prompted once for your current
password, and twice for your new password. Neither password will be displayed on the screen.
115
23. ps list processes
ps displays information on processes currently running on your machine. This information includes
the process id, the controlling terminal (if there is one), the cpu time used so far, and the name
of the command being run.
ps
gives brief details of your own processes in your current session.
To obtain full details of all your processes, including those from previous sessions use:-
ps -fu user1
using your own user name in place of user1.
ps is a command whose options vary considerably in dierent versions of Unix. Use man ps for
details of all the options available on the machine you are using.
24. pwd display the name of your current directory
The command pwd gives the full pathname of your current directory.
25. quota display disk quota and usage
quota gives information on a users disk space quota and usage.
On some systems using quota without options will only give details of where you have exceeded
your disk quota on local disks, in which case, use the -v option
quota -v
to get details of your quota and usage on all mounted lesystems.
26. rm remove les or directories
rm is used to remove les. In order to remove a le you must have write permission in its directory,
but it is not necessary to have read or write permission on the le itself.
rm le1
will delete the le le1. If you use
rm -i le1
instead, you will be asked if you wish to delete le1, and the le will not be deleted unless you
answer y. This is a useful safety check when deleting lots of les.
rm -r dir1
recursively deletes the contents of dir1, its subdirectories, and dir1 itself, and should be used with
suitable caution.
rm -rf dir1
is like rm -r, except that any write-protected les in the directory are deleted without query. This
should be used with even more caution.
116
27. rmdir remove a directory
rmdir removes named empty directories. If you need to delete a non-empty directory rm -r can
be used instead.
rmdir exdir
will remove the empty directory exdir.
28. sort sort and collate lines
The command sort sorts and collates lines in les, sending the results to the standard output.
If no le names are given, sort acts on the standard input. By default, sort sorts lines using a
character by character comparison, working from left to right, and using the order of the standard
character set.
sort -d
uses dictionary order, in which only letters, digits, and white-space characters are considered in
the comparisons.
sort -r
reverses the order of the collating sequence.
sort -n
sorts lines according to the arithmetic value of leading numeric strings. Leading blanks are ignored
when this option is used, (except in some System V versions of sort, which treat leading blanks
as signicant. To be certain of ignoring leading blanks use sort -bn instead.).
29. ssh secure remote login program
ssh is used for logging onto a remote machine, and provides secure encrypted communications
between the local and remote machines using the SSH protocol. The remote machine must be
running an SSH server for such connections to be possible. For example,
ssh -X YourCRSID@linux.phy.pwf.cam.ac.uk
will commence a login connection to the Physics PWF server.
You can connect using your password for the remote machine, or you can set up a system of
passphrases to avoid typing login passwords directly (see the man page for ssh-keygen for infor-
mation on how to create these).
The optional -X ag makes it possible for the remote machine to open X windows on your
local machine.
117
30. scp securely copy les between computers
scp is used for copying les between any two computers that you can log on to with ssh.
Suppose you could log in via ssh to computer computer1.co.uk with user-id britBoy on
which there was a le /var/allmypasswords.txt. And suppose that you wished to copy this le
to one called /home/ici.txt on a dierent computer ordinateur2.fr, which you are customarily
able to log into via ssh with user-id pierre. Then to eect that le transfer you would type the
following from a terminal on any computer:
scp britboy@computer1.co.uk:/var/allmypasswords.txt pierre@ordinateur2.fr:/home/ici.txt
If it so happened that the terminal from which you wanted to execute the scp command was
already on computer1.co.uk then you could use the simpler form:
scp /var/allmypasswords.txt pierre@ordinateur2.fr:/home/ici.txt
Likewise, if it so happened that the terminal from which you wanted to execute the scp command
was already on ordinateur2.fr then you could use the simpler form:
scp britboy@computer1.co.uk:/var/allmypasswords.txt /home/ici.txt
scp can also copy directories and all the contents recursively. To do the above on directories
one would need something like:
scp -r britboy@computer1.co.uk:/var pierre@ordinateur2.fr:/home
where the -r means Do this recursively on directories.
118