Assignments are to be done in groups of 2.
Although we do not need them in day-to-day use of computers, the concepts of filesystem paths become very important for programming. The most important of these are:
This is a collection of directories (folders) where executable files are looked for. The current set can be viewed by
$ echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/games
The compiler program gcc
resides in one such
directory, which is why we can invoke it by name. We can check
where it is actually located using
$ which gcc /usr/bin/gcc
The editor kate
is a similar program.
When we have statement like #include <stdio.h>
in a C program, this is essentially an instruction to include that
file in our program. Such files are searched for in some standard
locations, typically /usr/include/
and
/usr/local/include
. The files available for inclusion
in this way can be listed by
$ ls /usr/include
The output will contain several directories, and can be included
as well. For example, the file
/usr/include/gsl/gsl_randist.h
(if installed) declares
functions that generate pseudo-random numbers and are part of the GNU Scientific Library,
and these functions can be used in our programs by including the
header file as
#include <gsl/gsl_randist.h>
This is typically the directory where your source files are
present. After starting a terminal/console shell, you will normally
be at the so-called "home directory", (e.g.,
/home/guest/
). You can always check your current
working directory (CWD) using
$ pwd /home/guest/
We can change the CWD using the cd
command, followed
by the name of the destination folder. The folder name can be
either absolute (fully specified), or relative to the current
working directory. So the following two are equivalent:
$ cd /home/guest/programming/assignment1 $ cd programming/assignment1
This will only work if the folder
programming/assignment1
exists. Otherwise, you can create
it with
mkdir -p programming/assignment1
You can always return to the home directory by calling
cd
without any further arguments.
C programs should be written using a plain text editor (and not a word processor like Microsoft Word). Popular editors in GNU/Linux systems are Emacs, vi, gedit, and Kate. The first two are more powerful, but harder to learn. One can also use so-called Integrated Development Environments or IDEs (such as Visual Studio on Windows), but they are not as commonly used on Linux (at least for C programming).
The standard compiler on GNU/Linux is gcc
. For now,
we will explicitly execute gcc
whenever we want to
compile a program. Later we will learn about automating compilation
using Makefiles.
We will always compile C programs in the current working
directory. C program names should end with the extension
.c
. We will eventually write header files as well,
which should end with the extension .h
.
A C program file named myprogram.c
in the current
working directory can be compiled to an executable file called
myprogram
using the command
$ gcc -o myprogram myprogram.c
If the program uses functions from the math library by including
the header math.h
, it must be compiled using
$ gcc -o myprogram myprogram.c -lm
We will eventually work with multiple files, where the compilation may need to be done in several steps.
The resulting program can be executed using the command
$ ./myprogram
The initial dot (.
) refers to the current working
directory, and is needed because the current working directory is
not (usually) contained in the PATH
.
The purpose of this assignment is to serve as a simple
demonstration of how errors can occur in numerical computations.
Suppose we want to compute the value of 1 - cos(x)
for
a range of values of x
. We can do this directly (by
evaluating cos(x)
and subtracting from 1), but we could
also use the mathematically equivalent formula (sin(x) *
sin(x)) / (1 + cos(x))
. The question is, do the two methods
give the same answer, and if not, which one is better?
To investigate this question, write a C program called
evalerror.c
to evaluate the function 1 -
cos(x)
using the two methods above. The output should
contain three space-separated columns: the value x
and
the two evaluations.
Of course, the output depends on the grid of values of
x
at which the evaluation is done. Suppose this grid
is defined through a start point (A), an end point (B), and the
number (N) of equally spaced evaluation points in between. Your
program should be written in a way that allows this specification to
be made in the following three ways (assuming that the name of the
executable file is evalerror
):
$ ./evalerrorshould use the values
A = 0, B = 0.001, N = 200
. Use
the #define
construct for this. You can learn about
#define
from the K&R book, or here.
$ ./evalerror --askshould ask the user to enter these values interactively.
$ ./evalerror A B Nshould use the values entered in the command-line.
All other invocations should produce an error message and terminate the program.
For more fun, figure out a way to plot a curve of these values using R.
Submit your program by email by midnight of Monday January 30. Send me only the program file (C code), not any output.
Update: To see any differences, the evaluations should be printed using a "scientific notation" format; e.g., "%g" or "%.10g".