Some hints for Coursework 2
Types.
If numbers are to be treated as real numbers (float, double), make sure to add a .
behind them. For example, write 1./3.
instead of 1/3 .
Formatting.
Use \t to output tab (corresponds to pressing the tab key on the keyboard). This is useful for aligning tables.
cout << " Column1 \t Column2 \n";
Recurrence relations.
To deal with a two term recurrence relation x n
= f ( x n − 1
, x n − 2
) , one needs to keep track of the last two values of the recursion, say x_curr and x_old . In each iteration, x_curr is updated by x_curr = f(x_curr,x_old);
However, x_old also needs to “move one up”, that is, acquire the value that x_curr used to have before the update. This requires an auxiliary variable, say, x_temp .
x_temp = f(x_curr,x_old); x_old = x_curr; x_curr = x_temp;
Alternatively, one can change the order of assignments as follows x_temp = x_curr; x_curr = f(x_curr,x_old); x_old = x_temp;
If statements.
In C++, a the number 1 is evaluated to true, while 0 is evaluated to false. If, for example, a function returns values 0 or 1, then the statements if(f(x)) and if(f(x)==1) are equivalent.
Scoping.
In a C++ file, different variables can appear under the same name.
For example, a variable called iter may appear in a function and in the main() function. Despite having the same name, they are completely unrelated: a variable is only valid within its scope , that is, in the region between the {} braces in which it is declared!
Functions.
If the values in a two-term recurrence relation are to be updated by a function , then there are various ways to accomplish this. We illustrate
1
2 this with the recurrence relation from Problem (2.7)
(1) One can resort to recursion . This is when a function calls itself.
double p(int n) { if(n==0) return 1.; else if(n==1) return 1./3.; else return (19./3.)*p(n-1)-2.*p(n-2);
} gives the n -th value p ( n ) . Note that numerical errors can accumulate !
While the above solution computes the values of p(n) on demand, in some applications one might only need to be able to compute a value p(n) given the previous two values. The following shows two ways in which functions can be used to that end.
(2) Declare the variables x_curr and x_old in the main program and change them using call-by-reference in the function. For example, void f(double &p_curr, double& p_old) { double p_temp; p_temp = (19./3.)*p_curr-2.*p_old; p_old = p_curr; p_curr = p_temp;
}
(3) Alternatively, one can have the function return the new value of x_curr and only change x_old , as in double f(double x_curr, double& x_old) { double p_temp; p_temp = (19./3.)*p_curr - 2.*p_old;
// The value of x_old is updated p_old = p_curr; return p_temp;
}
There are many ways to solve the same problem in a computer program, though some solutions can be faster or more readable than others.
On the & operator.
A variable is a name for a space in memory where something (an integer, a floating point number, a character, etc) is stored.
When a variable is declared, then space is allocated for it, and labelled with the variable name. When a variable n is being used, then the value contained in the location labelled by n is used.
If n is passed as an
argument to a function, then the value contained in n is passed to the function, which it then stores in a different location within its own scope under that name. If we want a function to be able to change the content of the variable, then we need to give the function the address , rather than just its content/value. This is done using call-by-reference , with the & operator.
More details on this mechanism are discussed in Lecture 3.
3
Additional material.
It is highly recommended to read the lecture notes by Dr. Johnson on this course in addition to the slides and examples. A list of recommended literature can be found on the website.