Using a copy of table.c (written last week) as a guide, copy it into
graph.c and modify the declaration of z so that it is a two dimensional
array containing enough rows and columns into which the values of the function
are to be stored. You will also need to introduce two new integer variables to
control the loops. The template program. Here's a rough guide below:
#include <stdio.h> #include <math.h> #define ROWS 20 main() for (r = 0; r < ROWS;
r++) |
The text in red shows some of the modifications. Notice the #define lines near the top of the program and their usage down below to set the declaration of z. Because the loops now count in terms of r and c in steps of 1 from 0 upto the number of rows and columns (minus 1) in the z array, some mapping of row and column numbers onto x and y values will be required. You will therefore need extra variables stating the x and y limits over which z is to be calculated.
Assuming suitable double declarations for xstart, xfinish (and therefore
ystart, yfinish), the following fragment of C code will request values from the
user of your program:
printf("Enter starting and ending values for x:
"); scanf("%lf %lf",&xstart,&xfinish); |
Within the body of the innermost loop, the calculation of x (and similarly y)
will look something like:
x = xstart + r * (xfinish - xstart) / ROWS;
|
Finish off the program by printing out the values of the z array in the same way as last week's table.c program.
The program you have hopefully just written (graph.c) performs the following steps:
1. Ask the user for the range of x to be considered and input these values
into variables.
2. Ask the user for the range of y to be considered and
input these values.
3. Calculate the z array using a nested loop, printing
out the calculations as they are generated.
Notice that step 1 (and 2) can be split into two sub-steps as follows:
1a. Ask the user to type two numbers for the x range.
1b. Input the
numbers into two variables xstart, xfinish.
Modify step 3 (the loop within a loop part of the program) so that as well as
printing the values of
the elements of z, your program finds the maximum and
minimum values of the function calculation.
You will need two extra
variables zmax and zmin (declared as double) which should be initialised before
being involved in any calculations: zmax should initially be a very large
negative number (say -10000.0), zmin a very large positive number.
Every time a z[r][c] value is calculated, your program will have to ask if
its value is larger than zmax. If this is so, then the value of zmax should be
replaced with the z value.
if (z[r][c] > zmax) zmax = z[r][c]; |
You will need something similar to the above for the calculation of zmin too.
Use a printf statement after the outermost loop to display the values
of zmax and zmin along with
suitable explanatory text.
After testing your program (graph.c) you should notice that by the
time it prints out the maximum and minimum values of the function values
calculated, it has accumulated the function's values in the array z. Armed with
this information, your program can be augmented so that it prints out a
density plot or contour plot of your table of function values.
This is an old trick of using a series of single characters to replace a range
of values. The characters are chosen so that they appear to be increasing in
darkness (or lightness) when printed out in a square. For example:
.......... ..++++++.. .++++++++. .++****++. .++*##*++. .++****++. .++++++++. ..++++++.. .......... |
Immediately after the code to print out zmax and zmin, begin another two nested loops in terms of r and c with exactly the same control code (r = 0; r < ROWS; r++) etc.. as the loops used to calculate the z array.
Instead of using a printf statement to print out the value of z[r][c] as in
the previous loop, reduce the value of
z[r][c] into an integer number
between 0 and 4 (you already have the maximum values for z). The expression
will look something like:
((int) ((z[r][c] - zmin) / (zmax - zmin) * 4)) |
The int in brackets forces the calculation to produce an integer result
rather than a double floating point value) and use a switch statement
(you've not met this before) in preference to a series of if statements
to decide on what character to print for each value between 0 and 4.
switch ( ((int) ((z[r][c]
- zmin) / (zmax - zmin) * 4)) )
{ case 0: printf(" "); break; case 1: printf("."); break; case 2: printf("+"); break; case 3: printf("*"); break; case 4: printf("#"); break; } |
Apart from getting the brackets right, there's little to worry about a switch
statement which is just a more convenient way of handling more than one or two
conditions. Following the calculation of
the expression in the brackets
after switch, the program jumps to the case matching the value calculated.
In the above code, one of the printf statements will be executed. The
following break causes the
program to jump out of the switch statement to
the line following the closing curly bracket. It is important
that these
break statements not be omitted.
Remember to use printf to force a newline at end of each inner loop (the
column loop in terms of c)
printf("\n"); |
When you have successfully compiled your program, try running it with
different x,y ranges. Also consider
modifying the value of ROWS and COLUMNS
and even the function cos(2.0*x) * sin(y) to generate more interesting
contour plots.
Remember to print your fully functional copy of graph.c and paste it into
your log book.