Assignment 1

Groups

Assignments are to be done in groups of 2.

Background

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:

Path for executable programs

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.

Path for included header files

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>

Current/present working directory

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.

Writing and compiling C programs

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.

Assignment

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):

  1. Calling your program as
    $ ./evalerror
    should 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.
  2. Calling your program as
    $ ./evalerror --ask
    should ask the user to enter these values interactively.
  3. Calling your program as
    $ ./evalerror A B N 
    should 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".


Last updated: Fri Feb 10 2012