C Programming and Numerical Analysis
C Programming and Numerical Analysis
NOMURA
Mechanical Engineering
This book is aimed at those in engineering/scientific fields who have never learned programming
before but are eager to master the C language quickly so as to immediately apply it to problem
solving in numerical analysis. The book skips unnecessary formality but explains all the important
aspects of C essential for numerical analysis. Topics covered in numerical analysis include single and
simultaneous equations, differential equations, numerical integration, and simulations by random
numbers. In the Appendices, quick tutorials for gnuplot, Octave/MATLAB, and FORTRAN for
C users are provided.
ABOUT SYNTHESIS
This volume is a printed version of a work that appears in the Synthesis
Digital Library of Engineering and Computer Science. Synthesis lectures
provide concise original presentations of important research and
development topics, published quickly in digital and print formats. For
Synthesis Lectures on
store.morganclaypool.com
Mechanical Engineering
C Programming and
Numerical Analysis
An Introduction
Synthesis Lectures on
Mechanical Engineering
Synthesis Lectures on Mechanical Engineering series publishes 60–150 page publications
pertaining to this diverse discipline of mechanical engineering. The series presents Lectures
written for an audience of researchers, industry engineers, undergraduate and graduate
students.
Additional Synthesis series will be developed covering key areas within mechanical
engineering.
C Programming and Numerical Analysis: An Introduction
Seiichi Nomura
2018
Mathematical Magnetohydrodynamics
Nikolas Xiros
2018
Resistance Spot Welding: Fundamentals and Applications for the Automotive Industry
Menachem Kimchi and David H. Phillips
2017
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in
any form or by any means—electronic, mechanical, photocopy, recording, or any other except for brief quotations
in printed reviews, without the prior permission of the publisher.
DOI 10.2200/S00835ED1V01Y201802MEC013
Lecture #13
Series ISSN
Print 2573-3168 Electronic 2573-3176
C Programming and
Numerical Analysis
An Introduction
Seiichi Nomura
The University of Texas at Arlington
M
&C Morgan & cLaypool publishers
ABSTRACT
This book is aimed at those in engineering/scientific fields who have never learned programming
before but are eager to master the C language quickly so as to immediately apply it to problem
solving in numerical analysis. The book skips unnecessary formality but explains all the impor-
tant aspects of C essential for numerical analysis. Topics covered in numerical analysis include
single and simultaneous equations, differential equations, numerical integration, and simula-
tions by random numbers. In the Appendices, quick tutorials for gnuplot, Octave/MATLAB,
and FORTRAN for C users are provided.
KEYWORDS
C, numerical analysis, Unix, gcc, differential equations, simultaneous equations,
Octave/MATLAB, FORTRAN, gnuplot
vii
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
2 Components of C Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1 Variables and Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1.1 Cast Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.1.2 Examples of Data Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2 Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3 Operators between Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.1 Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.2 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.3 Increment/Decrement/Substitution Operators . . . . . . . . . . . . . . . . . . . 24
2.3.4 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4 Control Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.1 if Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.4.2 for Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.4.3 while Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.4.4 do while Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.4.5 switch Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
viii
2.4.6 Miscellaneous Remarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.4.7 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.5.1 Definition of Functions in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.5.2 Locality of Variables within a Function . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.5.3 Recursivity of Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.5.4 Random Numbers, rand() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.5.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.6 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.6.1 Definition of Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.6.2 Multi-dimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.6.3 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.6.4 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.7 File Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.7.1 I/O Redirection (Standard Input/Output Redirection) . . . . . . . . . . . . . 60
2.7.2 File Handling (From within a Program) . . . . . . . . . . . . . . . . . . . . . . . . 61
2.8 Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.8.1 Address Operator & and Dereferencing Operator * . . . . . . . . . . . . . . . . 63
2.8.2 Properties of Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.8.3 Function Arguments and Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.8.4 Pointers and Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.8.5 Function Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.8.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
2.8.7 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.9 String Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.9.1 How to Handle a String of Characters (Text) . . . . . . . . . . . . . . . . . . . 75
2.9.2 String Copy/Compare/Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
2.10 Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
2.10.1 Entering Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . 80
2.10.2 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
2.11 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.11.1 Mixture of Different Types of Variables . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.11.2 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
ix
4 Roots of f .x/ D 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.1 Bisection Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.2 Newton’s Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.2.1 Newton’s Method for a Single Equation . . . . . . . . . . . . . . . . . . . . . . . 102
4.2.2 Newton’s Method for Simultaneous Equations (Optional) . . . . . . . . . 106
4.2.3 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
xi
Preface
This book is aimed at those who want to learn the basics of programming quickly with imme-
diate applications to numerical analysis in mind. It is suitable as a textbook for sophomore-level
STEM students.
The book has two goals as the title indicates: The first goal is to introduce the concept
of computer programming using the C language. The second goal is to apply the programming
skill to numerical analysis for problems arising in scientific and engineering fields. No prior
knowledge of programming is assumed but it is desirable that the readers have a background in
sophomore-level calculus and linear algebra.
C was selected as the computer language of choice in this book. There have been con-
tinuous debates as to what programming language should be taught in college. Until around
the 1990s, FORTRAN had been the dominating programing language for scientific and en-
gineering computation which was gradually taken over by modern programming languages as
PASCAL and C. Today, MATLAB is taught in many universities as a first computer appli-
cation/language for STEM students. Python is also gaining popularity as a general purpose
programming language suitable as the first computer language to be taught.
Despite many options for the availability of various modern computer languages today,
adopting C for scientific and engineering computation still has several merits. C contains almost
all the concepts and syntax used in the modern computer languages less the paradigm of object-
oriented programming (use C++ and Java for that). It has been observed that whoever learns
C first can easily acquire other programming languages and applications such as MATLAB
quickly. The converse, however, does not hold. C is a compiled language and preferred over
interpreted languages for programs that require fast execution.
There is no shortage of good textbooks for the C language and good textbooks for numer-
ical analysis on the market but a proper combination of both seems to be hard to find. This book
is not a complete reference for C and numerical analysis. Instead, the book tries to minimize the
formality and limits the scope of C to these essential features that are absolutely necessary for
numerical analysis. Some features in C that are not relevant to numerical analysis are not covered
in this book. C++ is not covered either as the addition of object-oriented programming compo-
nents offers little benefit for numerical analysis. After finishing this book, the reader should be
able to work on many problems in engineering and science by writing their own C programs.
The book consists of two parts. In Part I, the general syntax of the C language is intro-
duced and explained in details. gcc is used as the compiler which is freely available on almost
all platforms. As the native platform of gcc is UNIX, a minimum introduction to the UNIX
operating system is also presented.
xii PREFACE
In Part II the major topics from numerical analysis are presented and corresponding C
programs are listed and explained. The subjects covered in Part II include solving a single equa-
tion, numerical differentiation, numerical integration, solving a set of simultaneous equations,
and solving differential equations.
In Appendix A, gnuplot which is a visualization application is introduced. The C lan-
guage itself has no graphical capabilities and requires an external program to visualize the output
from the program.
In Appendix B, a brief tutorial of Octave/MATLAB is given. This is meant for those who
are familiar with C but need to learn Octave/MATLAB in the shortest possible amount of time.
In Appendix C, a brief tutorial of FORTRAN is given. Again, this is meant for those who
are already familiar with C to be able to read programs written in FORTRAN (FORTRAN 77)
quickly.
This book is based on the course notes used for sophomore-level students of the Mechan-
ical and Aerospace Engineering major at The University of Texas at Arlington.
Seiichi Nomura
March 2018
xiii
Acknowledgments
I want to thank the students who took this course for their valuable feedback. I also want to
thank Paul Petralia of Morgan & Claypool Publishers and C.L. Tondo of T&T TechWorks,
Inc. for their support and encouragement.
All the programs and tools used in this book are freely available over the internet thanks
to the noble vision of the GNU project and the Free Software Foundation (FSF).
Seiichi Nomura
March 2018
PART I
Introduction to C Programming
3
In Part I, the basic syntax of the C language is introduced so that you can quickly write a pro-
gram for problems in science and engineering to be discussed in Part II. This is never meant
to be a complete reference for the C language. It covers only those items relevant to scien-
tific/engineering computation. However, after Part I, you should be able to explore missing
topics on your own. A minimum amount of computer environments is needed and all the pro-
grams listed should run on any version of gcc.
The only way to learn programming is to write a program by yourself. You never learn
programming if you just read books sitting on a sofa.
5
CHAPTER 1
$ nano MyProgram.c
The symbol, $, is the system prompt so do not type it. Enter the following text into nano.
Note that all the input in UNIX is case-sensitive.
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
4 nano is a simple editor that comes with all the installation of UNIX. It is a clone of another simple text editor, pico.
1.1. A CYCLE OF C PROGRAMMING 7
3. After you finish entering the text, save the file (Control-O5 ) by entering MyProgram.c6
as the file name to be saved and press Control-X to exit from nano. This will save the file
you just created permanently under the name of MyProgram.c.
4. The file you created with nano is a text file that is not understood by the computer. It is
necessary to translate this text file into a code which can be run on the computer. This
translation process is called compiling and the software to do this translation is called a
compiler. We use gcc for this purpose.
At the system prompt ($), run a C compiler (gcc) to generate an executable file (a.out7 ).
$ gcc MyProgram.c
If everything works, gcc will create an executable binary file whose default name is a.out.
• ls -lt j more (Directory listing, one screen at one time, long format, chronological order.)
• rm *.c (Do not do this. It will delete all the files with extension c.)
int main()
{
return 0;
}
You can compile and execute this program by issuing the following commands:
$ gcc MyProgram.c
$ ./a.out
where MyProgram.c is the name under which the file was saved. Even though it is the smallest
C program, the program itself is a full-fledged C code. Of course, this program does nothing
and when you issue ./a.out, the program simply exits after being executed and you are returned
to the system prompt.
Here is a line-by-line analysis of the program above. Refer to Section 1.3.1 for the list
of items. The first line, int main(), indicates that a function whose name is main is declared
that returns an integer value (int) upon exit (Item 4). This function takes no arguments (empty
parameters within the parentheses) (Item 5). The program consists of only one function, main(),
which is executed first (Item 7). The content of the function, main(), is the line(s) surrounded
by { and } (Item 6). In this case, the program executes the return 0 statement and exits back to
the operating system returning a 0 value to the operating system. As C is a free-form language,
the end of each statement has to be clearly marked. A semicolon ; is placed at the end of each
statement. Hence, return 0;.
The following program is a celebrated code that appeared first in the K&R book in the
Getting Started section and later adapted in just about every introductory book for C as the first
C program that prints “Hello, World!” followed by an extra blank line.
1:#include <stdio.h>
2:int main()
3:{
4:printf("Hello, World!\n");
5:return 0;
6:}
12 1. FIRST STEPS TO RUN A C PROGRAM
Each line in the above program is now parsed. The first line, #include <stdio.h>, is a bit
confusing but let’s skip this line for the time being and move to the subsequent lines. If you com-
pile the program and execute a.out, you will find out that the program prints Hello, World!
followed by a new line on the screen. Hence, you can guess that the odd characters, \n, repre-
sents a blank line. As there is no character that represents a blank line, you figure out that \n
can be used as printing a blank line.
Next, note that the part printf is followed by a pair of parentheses and therefore,
it is a function in C (Item 5). It is obvious that this function, printf(), prints a string,
Hello, World!, and quits. As it is a function in C, it has to be defined and declared before
it is used. However, no such definition is found above the function, main(). The first line,
#include <stdio.h>, is in fact referring to a file that contains the definition of printf() that
is preloaded before anything else. The file, stdio.h, is one of the header (hence the extension, h)
files available in the C library that is shipped with gcc. As the name indicates (stdio = Standard
Input and Output), this header file has the definition of many functions that deal with input
and output (I/O) functions.
Finally, a function must have information about the type of the value it returns such as
int, float, double, etc…(Item 4). In this case, the function int main() is declared to return
an integer value upon exit. Sure enough, the last statement return 0; is to return 0 when the
execution is done and 0 is an integer.
Here is how gcc parses this program line by line:
Line 1 Before anything else, let’s load a header file, <stdio.h>, that contains the definition of
all the functions that deal with I/O from the system area.
Line 2 This is the start of a function called main(). This function returns an integer value int
upon exit. This function has no parameters to pass so the content within the parentheses
is empty.
Line 3 The { character indicates that this is the beginning of the content of the function,
main().
Line 4 This line calls the function, printf(), that is defined in <stdio.h> and prints out a
string of Hello, World! followed by a blank line. A semicolon, ;, marks the end of this
function.
Line 5 This is the last statement of the function, main(). It will return the value 0 to the oper-
ating system and exit.
Line 6 The } character indicates the end of the content of the function, main().
You can execute this program by
$ nano hello.c
1.3. OVERVIEW OF C PROGRAMMING 13
(Enter the content of the program above.)
$ gcc hello.c
(If it is not compiled, reedit hello.c.)
$ ./a.out
Hello, World!
Here is another program that does some scientific computation.
1:#include <stdio.h>
2:#include <math.h>
3: /* This is a comment */
4:int main()
5: {
6: float x, y;
7: x = 6.28;
8: y=sin(x);
9: printf("Sine of %f is %f.\n", x, y);
10: return 0;
11:}
This program computes the value of sin x where x D 6:28. The program can be compiled
as
$ gcc MyProgram.c -lm
Note that the -lm10 option is necessary when including <math.h>.11
Here is a line by line analysis of the program:
Line 1 The program preloads a header file, <stdio.h>.
Line 2 The program also preloads an another header file, <math.h>. This header file is necessary
whenever mathematical functions such as sin.x/ are used in the program.
Line 3 This entire line is a comment. Anything surrounded by /* and /* is a comment and is
ignored by the compiler.12
Line 4 This is the declaration of a function, main(), that returns an integer value but with no
parameter.
10 “-l” is to load a library and “m” stands for the math library.
11 <math.h> only contains protocol declarations for mathematical functions. It is necessary to locally load the mathematical
library, libm.a by the -lm option.
12 A comment can also start with //. This for one-line comment originated in C++.
14 1. FIRST STEPS TO RUN A C PROGRAM
Line 5 The { character indicates that this is the beginning of the content of the function,
main().
Line 6 Two variables, x and y, are declared both of which represent floating numbers.
Line 8 The function, sin.x/, is evaluated where x is 6.28 and the result is assigned to the variable,
y.
Line 9 The result is printed. First, a literal string of “Sine of” is printed followed by the actual
value of x and “is” is printed followed by the actual value of y, a period and a new line.
Line 11 The } character indicates that this is the end of the content of the function, main().
There are several new concepts in this program that need to be explained. The second line
is to preload yet another header file, math.h, as this program computes the sine of a number.
In the fourth line, two variables, x and y, are declared. The float part indicates that the two
variables represent floating numbers (real numbers with the decimal point). The fifth line says
that a number, 6.28, is assigned to the variable, x. The equal sign (=) here is not the mathematical
equality that you are accustomed to. In C and all other computer languages, an equal sign (=)
is exclusively used for substitution, i.e., the value to the right of = is assigned to the variable
to the left of =. In the eighth line, the printf() function is to print a list of variables (x and
y) with formating specified by the double quotation marks (“...”). The way formating works is
that printf() prints everything literally within the parentheses except for special codes starting
with the percentage sign (%). Here, %f represents a floating number which is to be replaced by
the actual value of the variable. As there are two %f’s, the first %f is replaced by the value of x
and the second %f is replaced by the value of y. The details of the new concepts shown here will
be explained in detail in Chapter 2.
1.4 EXERCISES
It is not necessary to know all the syntax of C to work on the following problems. Each problem
has a template that you can modify. Start with the template code, keep modifying the code and
understand what each statement does. It is essential that you actually write the code yourself
(not copy and paste) and execute it.
1. Write a C program to print three blank lines followed by “Hello, World!”. Use the follow-
ing code as a template:
1.4. EXERCISES 15
#include <stdio.h>
int main()
{
printf("\nHello, World!\n\n");
return 0;
}
2. Write a program to read two real numbers from the keyboard and to print their product.
Use the following code as a template. Do not worry about the syntax, just modify one
place.
#include <stdio.h>
int main()
{
int a, b; /* to declare that a and b are integer variables */
printf("Enter two integer numbers separated by space =");
scanf("%d %d", &a, &b); /* This is the way to read two integer
numbers and assign them to a and b. */
printf("The sum of the two numbers is %d.\n", a+b); /* %d is for
integer format. */
return 0;
}
3. Write a program to read a real number, x , and outputs its sine, i.e., sin.x/. You need to use
<math.h> and the -lm compile option. Use the following template program that computes
ex .
#include <stdio.h>
#include <math.h>
int main()
{
float x;
printf("Enter a number ="); scanf("%f", &x);
printf("x= %f exp(x)=%f\n",x, exp(x));
return 0;
}
16 1. FIRST STEPS TO RUN A C PROGRAM
You have to use the -lm option when compiling:
CHAPTER 2
Components of C Language
In this chapter, the essential components of the C language are introduced and explained. The
syntax covered in this chapter is not exhaustive but after this chapter you should be able to write
a simple C program that can solve many problems in engineering and science.
In Table 2.1, the third column shows the format of each data type which is used in the
print() and scanf() functions.
• int represents an integer value. The range of int depends on the hardware and the ver-
sion of the compiler. In most modern systems, int represents from -2147483647 to
2147483647.
• float represents a floating number. This will take care of most non-scientific floating
numbers (single precision). For scientific and engineering computation, double must be
used.
• double is an extension of float. This data type can handle a larger floating number at the
expense of the amount of memory used (but not much).
• char represents a single ASCII character. This data type is actually a subset of int in which
the range is limited to 0 255. The character represented by char must be enclosed by a
single quotation mark (').
18 2. COMPONENTS OF C LANGUAGE
2.1.1 CAST OPERATORS
When an operation between variables of different types is performed, the variables of a lower
type are automatically converted to the highest type following this order:
int=char < float < double
For example, for a * b in which a is of int type and b is of float type, then, a is
converted to the float type automatically and the result is also of float type. There are times
when two variables are both int type yet the result of the operation is desired to be of float
type. For example,
#include <stdio.h>
int main()
{
int a, b;
a=3; b=5;
printf("%f\n", a/b);
return 0;
}
The output is
$ gcc prog.c
2.c: In function 'main':
2.c:6:10: warning: format '%f' expects argument of type 'double',
but argument 2 has type 'int' [-Wformat=]
printf("%f\n", a/b);
^
$ ./a.out
-0.000000
It prints 0 with a warning even though the result is expected to be 0.6. To carry out this operation
as intended,1 a cast operator (an operator to allow to change the type of a variable to a specified
type temporarily) must be used as
#include <stdio.h>
int main()
{
int a,b;
a=3;b=5;
printf("%f\n", (float)a/b);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
0.600000
The (float)a/b part forces both variables to be of float type and returns 0.6 as expected.
/*
Print a character
*/
#include <stdio.h>
int main()
{
char a='h';
printf("%c\n",a);
return 0;
}
Note that the variable, a, is declared as char and initialized as “h” on the same line.
2. This program prints an integer 10.
/*
Print an integer
*/
#include <stdio.h>
int main()
{
int a=10;
printf("%d\n",a);
20 2. COMPONENTS OF C LANGUAGE
return 0;
}
Note that the variable, a, is declared as int and initialized as 10 on the same line.
3. This program prints a floating number 10.5.
Note that the variable, a, is declared as float and initialized as 10.5 on the same line.
4. This program prints two floating numbers, 10.0 and -2.3.
2.2 INPUT/OUTPUT
Almost all C programs have at least one output statement. Otherwise, the program won’t output
anything on the screen and there is no knowing if the program ran successfully or not. The most
common input/output functions are printf() and scanf() both of which are defined in the
header file stdio.h.
Use printf() (Print with Format) for outputting data to the console and scanf() (Scan
with Format) for inputting data from the keyboard.
2.2. INPUT/OUTPUT 21
• printf()
The syntax of the printf() function is
printf("format",argument);
where format is the typesetting of the output that you can control and argument is a
list of variables to be printed. The printf() function prints the value(s) of variables in
argument to the standard output (screen) following the formatting command defined by
format.
Examples:
printf("Hello, World!\n");
printf("Two integers are %d and %d.\n",a,b);
printf("Two floating numbers are %f and %f.\n",a,b);
printf("Three floating numbers are %f, %f and %f.\n",a,b,c);
A string of characters surrounded by the double quotes (") is printed. However, the per-
centage sign (%) plus a format letter is automatically replaced by the value of a variable
followed. Use %d for an integer, %f for a floating number, %lf for a double precision num-
ber, and %c for a character. The backslash (\) is called the escape character and escapes
the following letter. \n represents the next line (inserting a blank line), \t represents a tab
character and \a rings the bell. If you want to print the double quotation mark ("), use \".
To print the backslash (\) itself, use \\.
• scanf()
The scanf() is the inverse of printf(), i.e., it scans the value(s) of variable(s) from the
standard input (keyboard) with format. The formatting part (i.e., % …) in scanf() is the
same as printf(). However, the variable name must be preceded by an & (ampersand).
The reason why an & is required for scanf() but not for printf() will be clarified in
Section 2.8 (pointers).
Compare the following two programs:
#include <stdio.h>
int main()
{
int a, b;
22 2. COMPONENTS OF C LANGUAGE
The output is
$ gcc prog.c
$ ./a.out
Enter two integers separated by a comma = 12, 29
a=12 b=29
This program expects that two values are entered from the keyboard separated by a comma (,)
because of "%d, %d" in the scanf() function. You have to type the comma (,) immediately
after the first number. The second number can be entered after as many spaces as you want.
#include <stdio.h>
int main()
{
int a; float b;
printf("Enter an integer and a real number separated by a space = ");
scanf("%d %f",&a, &b);
printf("a=%d b=%f\n", a, b);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter an integer and a real number separated by a space = 21 6.5
a=21 b=6.500000
In this program, two numbers must be entered separated by a space. The number of spaces is
arbitrary.
Symbol Meaning
< a < b ; a is less than b.
<= a <= b ; a is less than or equal to b.
> a > b ; a is greater than b.
>= a >= b; a is greater than or equal to b.
== a = = b ; a is equal to b.
!= a!= b ; a is not equal to b.
Examples
1. if (a==b) printf("a and b are equal.\n");
else printf("a and b are not equal.\n");
The statement above means that if the two variables, a and b, are the same, a string, “a and
b are equal.”, is printed, otherwise a string, “a and b are not equal.”, is printed.
Note the difference between one equal sign (=) and two equal signs (==). One equal sign
is for assignment and two equal signs are for logical equality. The double equal signs in C
are equivalent to the equal sign in regular mathematical equations.
2. a = 10;
a = a + 1;
The single equal sign in C represents an action to assign the value to the right of the equal
sign to the variable to the left of the equal sign. The statement a = a + 1 does not make
sense as a mathematical expression. However, it makes perfect sense as a C statement. a
+ 1 is first evaluated to be 11 and this value of 11 is then assigned to a. Effectively, the
value of a was incremented by 1.
Symbol Meaning
&& And
|| Or
! Not
int a=20;
if (!(a==10)) printf("a is not equal to 10.");
if (a==10)
{ printf("The value of a is 10.\n");
return 0;
}
else ....
Symbol Meaning
++ b = ++ a a is incremented by 1 and assigned to b. Same as a = a + 1; b = a;
b = a ++ a is assigned to b first and incremented by 1. Same as b = a; a = a + 1;
–– b = –– a a is decremented by 1 and assigned to b. Same as a = a – 1; b = a;
b = a –– a is assigned to b first and decremented by 1. Same as b = a; a = a – 1;
+= a += b a + b is assigned to a. Same as a = a + b;
‒= a ‒= b a – b is assigned to a. Same as a = a – b;
*= a *= b a * b is assigned to a. Same as a = a * b;
/= a /= b a / b is assigned to a. Same as a = a / b;
%= a %= b Remainder of a=b is assigned to a. Same as a = a%b;
i+=1;
i++;
++i;
The difference between ++i and i++ is that the former pre-increments i before any operation
while the latter post-increments i after the operation is done.
2.3.4 EXERCISES
1. Write a program that interactively reads temperature in Celsius and convert it to Fahren-
heit. Note
5
C D .F 32/ :
9
Expected output:
$ ./a.out
Enter temperature in C = 29
It is 84.2 degrees in Fahrenheit.
• for ( ; ; )
• while
• do while
• switch
2.4.1 IF STATEMENT
A block (a set of statements surrounded by { and }) following the if statement is executed when
the condition inside (: : :) is satisfied. If there is no block, the next statement is executed. else
is optional.
The following program tells whether an integer entered from the keyboard is between 1
and 100 or not:
#include <stdio.h>
int main()
{
int i;
printf("Enter an integer = ");
scanf("%d",&i);
if (i>1 && i<100)
printf("The number is between 1 and 100.\n");
else
printf("The number is not in that range.\n");
return 0;
}
$ gcc prog.c
$ ./a.out
Enter an integer = 45
The number is between 1 and 100.
$ ./a.out
Enter an integer = 104
The number is not in that range.
2.4. CONTROL STATEMENTS 27
2.4.2 FOR STATEMENT
A for loop is to be used when the number of iterations to be executed is known in advance. The
for loop consists of three parts each of which is separated by a semicolon (;). The first part is
initialization of a counter variable, the second part is a test of the iteration counter variable and
if this test fails, the loop is finished. The third part defines an action on the counter variable. A
block can be followed after the for statement to execute multiple statements for each iteration.
for (initial value; condition ; counter increment) statement;
Examples
1. The following program prints 0–9.
#include <stdio.h>
int main()
{
int i;
for (i=0; i< 10; i++) printf("i=%d\n",i);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
S D 1 C 2 C 3 C 4 C 5 C 6 C : : : C 100:
28 2. COMPONENTS OF C LANGUAGE
#include <stdio.h>
int main()
{
int i, sum = 0;
for (i=0; i<= 100; i++) sum = sum + i;
printf("Sum = %d\n", sum);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Sum = 5050
In this program, i is a counter variable and sum is a placeholder for the sum. The parameters
in the for statement mean that the counter variable, i, is reset to be 0 first and as long
as i is less than or equal to 100, the sum = sum + 1 statement is repeated. Upon each
execution of sum = sum + 1, i is incremented by 1. In the sum = sum + 1 statement,
the previous value of sum is incremented by 1 at each iteration and the newly incremented
value of sum+1 replaces the previous value of sum.
The following pattern can compute mathematical summation:
sum = 0.0;
for (i=0; i<= 100; i++) sum = sum + f(i);
for
100
X
f .i / D f .0/ C f .1/ C f .2/ C : : : C f .100/:
i D0
To implement the left-hand side of Eq. (2.2) in C, use the following statement:
#include <stdio.h>
#include <math.h>
int main()
{
int i,n;
float sum=0.0;
printf("Enter # of iterations = ");
scanf("%d", &n);
for (i=1;i<n;i++)
sum = sum + pow(-1, i+1)/i;
printf("Approximation of ln(2)= %f. ", sum);
printf("Exact value of ln(2)= %f.\n", log(2));
return 0;
}
The output is
As is seen from the output above, the convergence of the series is rather slow. Also note
that for today’s computers, iterations for 10,000,000 times pose no problem whatsoever.
x3 C x 1 D 0; (2.3)
1
xD : (2.4)
1 C x2
Although Eqs. (2.3) and (2.4) are mathematically equivalent, Eq. (2.3) cannot be used as
a valid C statement while Eq. (2.4) can be used as a valid C statement where the evaluated
1
value of 1Cx 2 is assigned to x . Starting with appropriate initial guess for x , Eq. (2.4) can be
iterated until convergence is attained. The following program uses x D 1 as initial guess:
#include <stdio.h>
int main()
{
int i,n;
float x=1.0;
printf("Enter # of iterations = ");
scanf("%d", &n);
for (i=1;i<n;i++) x = 1/(1+x*x);
printf("Iteration #=%d, x=%f.\n", i, x);
return 0;
}
The output is
2.4. CONTROL STATEMENTS 31
$ gcc prog.c
$ ./a.out
Enter # of iterations = 30
Iteration #=30, x=0.682327.
$ ./a.out
Enter # of iterations = 31
Iteration #=31, x=0.682328.
$ ./a.out
Enter # of iterations = 32
Iteration #=32, x=0.682328.
It is seen that the convergence was attained after 31 iterations. Although the convergence
with this iteration method is slow, there is no need to use any advanced mathematics to
solve this cubic equation.
#include <stdio.h>
int main()
{
int i=0;
while (i<10) i++;
printf("%d\n",i);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
10
It appears that the program should output 9, not 10. However, in the test i<10 when i=9, i is
incremented to 10 and this value is held thereafter.
For multiple statements, it is necessary to use a block with curly brackets ({ and }).
32 2. COMPONENTS OF C LANGUAGE
#include <stdio.h>
int main()
{
int i=0;
while (i<10)
{i++;
printf("i = %d\n",i);
}
printf("%d\n",i);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
10
#include <stdio.h>
int main()
{
2.4. CONTROL STATEMENTS 33
int input_value;
do
{ printf("Enter 1 for yes, 0 for no :");
scanf("%d", &input_value);
} while (input_value != 1 && input_value != 0);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter 1 for yes, 0 for no :10
Enter 1 for yes, 0 for no :2
Enter 1 for yes, 0 for no :-1
Enter 1 for yes, 0 for no :0
#include <stdio.h>
int main()
{
int i;
printf("Enter an integer="); scanf("%d", &i);
switch(i)
{
case 1: printf("a is 1\n");break;
case 2: printf("a is 2\n");break;
default: printf("a is neither 1 nor 2\n");break;
}
return 0;
}
The output is
34 2. COMPONENTS OF C LANGUAGE
$ gcc prog.c
$ ./a.out
Enter an integer=12
a is neither 1 nor 2
$ ./a.out
Enter an integer=2
a is 2
It is important to use a break statement to break out from the block for each statement
executed. Note that a colon (:) must be used instead of a semicolon (;) after case.
From time to time, the program you wrote may be trapped in an infinite loop and nothing
can be done except for closing the window or shutting down the machine. For instance,
the following program generates an infinite loop:
#include <stdio.h>
int main()
{
int i;
for (i=1; i>0; i++) printf("loop");
return 0;
}
2.4. CONTROL STATEMENTS 35
• Output formatting
It is possible to modify the appearance of the output from the printf() function. Study
the following format control codes used in the printf() statement:
#include <stdio.h>
int main()
{
float a=3.14;
printf("%f\n",a);
printf("%10f\n",a);
printf("%20f\n",a);
printf("%30f\n",a);
printf("%10.3f\n",a);
printf("%10.4f\n",a);
printf("%10.5f\n",a);
printf("%10.6f\n",a);
return 0;
}
4 Hold down the control key and press C. Also if the screen is suddenly frozen and does not accept any keyboard input, try
control-Q. This is usually caused by accidentally entering control-S (for pausing output).
36 2. COMPONENTS OF C LANGUAGE
The output is
$ gcc prog.c
$ ./a.out
3.140000
3.140000
3.140000
3.140000
3.140
3.1400
3.14000
3.140000
The format, %10.6f means that 10 spaces from the beginning of the line are reserved and
the float variable is printed with 6 decimal places right justified. This formatting option is
purely cosmetic and does not change the actual value of the variable.
• What is a=b=20 ?
A statement such as a=b=20 looks strange but it is an acceptable C statement. Try running
the following code:
#include <stdio.h>
int main()
{
float a, b;
printf("%f\n", a=20.0);
b=a=30.0;
printf("%d\n", a==20.0);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
20.000000
0
2.4. CONTROL STATEMENTS 37
In the statement, a=b=20, the control goes toward the end of the line. Hence, b=20 is first
executed in which b is assigned 20 but also the statement, b=20, itself is assigned the same
value (20) which is subsequently assigned to a. This way, one can assign 20 to both a and
b at the same time. In the program above, after b=a=30.0, the value of a is 30. Therefore,
a==20.0 is false and hence the printf() function returns 0 (false).
• In gcc, you can use the -o5 option to specify the name of the executable file instead of
a.out.
This generates an executable binary, MyProgram, instead of the default file, a.out, in
the same directory. For the Windows version of gcc, the name of the executable is
MyProgram.exe.
#include <stdio.h>
#define PI 3.141592 /* Defines pi. */
int main()
{
float a;
printf("Enter radius = ");
scanf("%f", &a);
printf("The area of circle is=%f.\n", a*a*PI);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter radius = 2.0
The area of circle is=12.566368.
Whenever the C compiler encounters PI, the compiler replaces PI by 3.141592. It is cus-
tomary to use upper case letters to define constants with the #define preprocessor.
5o for output.
38 2. COMPONENTS OF C LANGUAGE
• Why does the return 0; in int main() have to return 0?
Returning 0 is not absolutely necessary. In fact, return -1; or return 2019; works just
fine. However, by returning 0 to the operating system when int main() exits, the oper-
ating system knows that the process finished normally and continues to run accordingly.
It does the operating system a favor by telling the operating system that it does not have
to bother to do anything special.
2.4.7 EXERCISES
1. Write a C program that interactively reads the three coefficients of a quadratic equation
and compute the two roots. The program must alert if there is no real root. The quadratic
equation is given by
ax 2 C bx C c D 0;
and the two roots are expressed as
p
b˙ b2 4ac
xD :
2a
Note: sqrt is available in <math.h>. You need to compile the program with the -lm op-
tion, i.e.,
. 1/nC1
an D ; n D 1; 2; 3 : : :
2n 1
6 Start with the geometric series of
1
D1 x2 C x4 x6 C x8 :::
1 C x2
Integrate both sides to get
x3 x5 x7 x9
arctan x D x C C :::
3 5 7 9
Substitute x D 1 in the above to get
1 1 1 1
arctan 1 D D1 C C :::
4 3 5 7 9
2.5. FUNCTIONS 39
2.5 FUNCTIONS
2.5.1 DEFINITION OF FUNCTIONS IN C
The concept of functions in C is important as after all a C program is defined as a set of functions.
You have already seen an example of C function, main(), which is always executed first.
That is the only special property with main(), which means that any function in C must follow
the same syntax as main(), i.e., declaration of the type (int for main()), argument(s) within
the parentheses (leave it blank if none), all the statements within { and }, and return value
as the last line in main(). If the function does not need any return value, use void as the type
of return value.
Examples
1. The following program shows an example of the type, void. All the user-defined function,
write(),7 does is to print “Hello World!” and it does not return any value upon exit.
Therefore, it has to be declared as void.
#include <stdio.h>
void write()
{
printf("Hello, World!\n");
}
int main()
{
write();
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Hello, World!
As the function, write(), does not have any parameter to pass, it has to be called without
any argument as write() in the main function.
2. The following program defines a function, cube(), which returns the cube of a parameter,
x:
#include <stdio.h>
float cube(float x)
{
return x*x*x;
}
int main()
{
float x;
printf("Enter x = "); scanf("%f",&x);
printf("The cube of x is %f.\n", cube(x));
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter x = 3
The cube of x is 27.000000.
Upon exit, cube(x) returns x 3 with x as the argument passed from the main function.
3. The following program computes x y (x to the power of y )8 using its own function,
power(), instead of the pow()9 function available in <math.h>:
#include <stdio.h>
#include <math.h>
float power(float x, float y)
{
return exp(y*log(x));
}
int main()
{
float x,y;
printf("Enter x and y separated by space =");
scanf("%f %f",&x,&y);
if (x<0)
{
printf("x must be positive !!\n");
return 0;
}
printf("%f to power of exponent %f is %f.\n", x, y, power(x,y));
return 0;
}
The output is
The program exits if x is negative. Otherwise, it computes x y and prints its value.
#include <stdio.h>
int f(int n)
{
int i,sum=0;
for (i=1;i<= n;i++) sum=sum+i;
return sum;
}
int main()
{
int i, sum=0;
for (i=1;i <= 10;i++) sum=sum+i*i;
printf("%d %d\n", sum, f(10));
42 2. COMPONENTS OF C LANGUAGE
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
385 55
The printed value of sum is the sum defined in main() even though a variable of the same name
is returned in the function, f().
Examples
1. Fibonacci numbers
The Fibonacci numbers, an , are defined as
an D an 1 C an 2; a1 D 1; a2 D 1: (2.5)
#include <stdio.h>
int fibo(int n)
{
if (n==1) return 1;
if (n==2) return 1;
return fibo(n-1) + fibo(n-2);
}
10 In old languages such as FORTRAN, recursivity is not supported.
11 There is an interesting background story with this number. See www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fi
bonacci/fibnat.html#Rabbits.
2.5. FUNCTIONS 43
int main()
{
int i;
printf("Enter n = "); scanf("%d", &i);
printf("%d\n", fibo(i));
return 0;
}
$ gcc prog.c
$ ./a.out
Enter n = 12
144
1 C 2 C 3 C ::: C n
#include <stdio.h>
int sum_of_integers(int n)
{
if (n==0) return 0;
return n + sum_of_integers(n-1);
}
int main()
{
int n;
printf("Enter n = ");
scanf("%d", &n);
printf("1+2+....+%d =%d \n", n, sum_of_integers(n));
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter n = 100
1+2+....+100 =5050
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
for (i=0; i < 10; i++) printf("%d\n", rand());
printf("\nMAX = %d\n", RAND_MAX);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
1804289383
846930886
2.5. FUNCTIONS 45
1681692777
1714636915
1957747793
424238335
719885386
1649760492
596516649
1189641421
MAX = 2147483647
The function, rand(), returns an integer between 0 and RAND_MAX (system dependent)13 which
is defined in the header file, <stdlib.h>.14
If floating random numbers between 0 and 1.0 are desired instead of between 0 and
RAND_MAX, the following program is used:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
for (i=0; i< 10; i++) printf("%f\n", 1.0*rand()/RAND_MAX);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
0.840188
0.394383
0.783099
0.798440
0.911647
0.197551
0.335223
0.768230
13 2147483647 for most systems. It is the maximum integer value handled by the system.
14 stdlib = standard library.
46 2. COMPONENTS OF C LANGUAGE
0.277775
0.553970
Note the %f format and the factor of 1.0. The value of rand()/RAND_MAX alone returns 0 as
both rand() and RAND_MAX are integers and the result is a truncated integer.
However, the same numbers are output again and again each time the program is run.
They are all predictive and not random numbers. In order to generate a different sequence of
random numbers each time the program is run, srand()15 available in <stdlib.h> must be
used in conjunction with rand(). The srand() function sets its argument as the seed for a new
sequence of pseudo-random integers to be returned by rand(). These sequences are repeatable
by calling srand() with the same seed value. If no seed value is provided, the rand() function
is automatically seeded with a value of 1.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
printf("Enter seed integer = ");
scanf("%d", &i);
srand(i);
printf("%d\n", rand());
return 0;
}
$ gcc prog.c
$ ./a.out
Enter seed integer = 10
1215069295
In the program above, srand(i) takes a seed number i and generates a random number based
on the value of i. The problem with this approach is that if the same seed number is given, the
rand() function returns the same value.
Using the time() function defined in <time.h>, you can generate a different seed num-
ber every time. The function, time(), with the argument NULL returns the elapsed time since
00:00:00 GMT, January 1, 1970,16 measured in seconds.
15 srand = seed random.
16 This is the birthday of UNIX!
2.5. FUNCTIONS 47
#include <stdio.h>
#include <time.h>
int main()
{
int i;
printf("%d\n", time(NULL));
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
1344034011
At the time of writing, 1,344,034,011 seconds have passed since 1/1/1960. As this value keeps
increasing, it can be used as a seed number for srand(). The following program generates a
different random number every time it is called.17
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(NULL));
printf("%d\n", rand());
return 0;
}
$ gcc prog.c
$ ./a.out
1819029242
(Wait a few seconds.)
$ ./a.out
1672748932
17 If the program is run twice within 1 second, the same random number is generated.
48 2. COMPONENTS OF C LANGUAGE
Generating Random Numbers in Various Ranges
With an integer number generated by rand() and MAX_RAND, it is possible to convert this num-
ber to any range, be it an integer range or a float number range. The following list shows examples
of various ranges generated by rand():
6. rand()%7+10 returns an integer of 10, 11, 12, 13, 14, 15, or 16.
This integration represents the shaded area in Figure 2.1. As it is a quarter of the whole unit
y = 1– x 2
0
x
1
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#define PI 3.141592
int main()
{
float x, y;
int i, count=0;
int n;
printf("Enter iteration number = ");scanf("%d", &n);
srand(time(NULL));
for (i=0; i< n; i++)
{
x=1.0*rand()/RAND_MAX;
y=1.0*rand()/RAND_MAX;
if (x*x+y*y < 1.0) count=count+1;
}
printf("True value = %f\n", PI/4);
printf("Appx value = %f\n", 1.0*count/n);
return 0;
}
As is seen in the output above, the convergence by the Monte Carlo method is at best mediocre
and should be used only as the last resort for 1D integrals. However, the Monte Carlo method
is a quick way to approximate 2D and higher-dimensional integrals.
2.5.5 EXERCISES
1. A sequence an is given with the following rule:
anC2 D 2anC1 C 3an ; a0 D 2; a1 D 1:
Write a C program to compute a17 .
2. (a) Write a function, int factorial(int n), which returns nŠ (the factorial of n, i.e.,
1 2 3 : : : n) using the recursive algorithm.
(b) Using int factorial(int n) above, write a program to compute
1 1 1
1C C C ::: C :
1Š 2Š 11Š
3. Using the Monte Carlo method, integrate
Z 1
1
dx;
0 1 C x2
numerically. Vary the number of iterations (10, 100, 1,000) and estimate an appropriate
number of iterations to obtain good accuracy. Note: The exact value of the above integra-
tion is =4 so this can be also used to approximate the value of .
4. Using the Monte Carlo method, estimate the volume of the unit sphere
x 2 C y 2 C z 2 1:
2.5. FUNCTIONS 51
5. Using the Taylor series for cos.x/ expressed as
x2 x4 x6
cos .x/ D 1 C C ::: (2.6)
2Š 4Š 6Š
create your own cos.x/ and demonstrate your program by making a table which may look
like the one shown in Table 2.5, where mycos(x) is from your program and cos .x/ is the
math function defined in <math.h>.
Table 2.5: cos.x/ table
x mycos(x) cox(x)
0.0 1.000 1.000
0.1 1.101 1.105
0.2 1.308 1.221
… … …
1.0 1.69 1.781
Note:
(a) The values above are false.
(b) Equation (2.6) can be written as
1
X . 1/i x 2i
cos.x/ D :
.2i/Š
iD0
#include <stdio.h>
#include <math.h>
int factorial(int n)
{
(your code here)
}
float mycos(float x)
{
float sum=0; int i;
for (i=0;i<=10;i++) sum = sum + (your code here);
52 2. COMPONENTS OF C LANGUAGE
return sum;
}
int main()
{
float ...;
int i=1; /* counter */
2.6 ARRAYS
Vectors and matrices in linear algebra can be implemented in C as arrays. An array in C can
represent many elements by a single variable name. This section explains the basic concept of
arrays. Arrays are closely related to pointers in C which will be further explained in Section 2.8.
#include <stdio.h>
int main()
{
float a[3];
a[0]=1.0; a[1]=2.0; a[2]=5.0;
(.......)
return 0;
}
The program above defines an array, a, which represents three elements. The values, 1.0, 2.0, and
5.0, are assigned to the first element, the second element and the third element of a, respectively.
Note that the index in arrays begins with 0 rather than 1 and ends with n 1 where n is the
number of elements. This poses a little confusion when arrays are used to represent matrices or
vectors in linear algebra as the index in linear algebra begins at 1 so care must be taken when
manipulating vector/matrix indices. You can initialize arrays at the same time they are declared
as
2.6. ARRAYS 53
#include <stdio.h>
int main()
{
float a[3]={1.0, 2.0, 3.0};
(......)
return 0;
}
or simply,
#include <stdio.h>
int main()
{
float a[]={1.0, 2.0, 3.0};
(......)
return 0;
}
i.e., if an array is initialized, its dimension can be omitted as the number of elements is auto-
matically determined.
The following program computes the sum of all the numbers in an array:
#include <stdio.h>
#define N 5
int main()
{
int i;
float a[N]={2.0, -15.0, 12.0, -5.4, 1.9};
float sum=0.0;
for (i=0;i <N;i++) sum = sum + a[i];
printf("The sum is = %f.\n", sum);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
The sum is = -4.500000.
54 2. COMPONENTS OF C LANGUAGE
2.6.2 MULTI-DIMENSIONAL ARRAYS
Arrays can be nested, i.e., they can take more than 1 indices. Nested arrays (multi-dimensional
arrays) can represent matrices in linear algebra. For example, the components of a 2 5 matrix,
a, can be represented in C as
aŒ0Œ0 aŒ0Œ1 aŒ0Œ2 aŒ0Œ3 aŒ0Œ4
aD :
aŒ1Œ0 aŒ1Œ1 aŒ1Œ2 aŒ1Œ3 aŒ1Œ4
#include <stdio.h>
#define COL 5
#define ROW 2
int main()
{
int i,j;
float mat[ROW][COL]={{1.0 ,2.0 ,3.0, 4.0 ,5.0},{6.0, 7.0,
8.0, 9.0, 10.0}};
for (i=0;i<ROW;i++)
{for (j=0;j<COL;j++)
printf("%f ", mat[i][j]); printf("\n");}
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
1.000000 2.000000 3.000000 4.000000 5.000000
6.000000 7.000000 8.000000 9.000000 10.000000
2.6. ARRAYS 55
2.6.3 EXAMPLES
1. Standard deviation and variance
The average of a sequence, fx1 ; x2 ; x3 ; : : : xn g, is the arithmetic average of the components
defined as
N
1 X
XN xi :
N
i D1
Note the factor, N 1, instead of N in Eq. (2.7). This is a mathematical necessity. The
standard deviation, sx , having the dimension of xi , is defined as
v
u N
u 1 X
sx t .xi XN /2 :
N 1
i D1
The following program computes the average and the standard deviation of 10 data points:
#include <stdio.h>
#include <math.h>
#define N 10
int main()
{
float a[N]={0.974742, 0.0982212, 0.578671, 0.717988, 0.881543,
0.0771773, 0.910513,0.576627, 0.506879, 0.629856};
float sum=0, average, var=0, sd;
int i;
for (i=0;i<N;i++) sum=sum+a[i];
average=sum/N;
for (i=0;i<N;i++) var=var+pow( a[i]-average, 2);
sd=sqrt((var)/(N-1.0));
printf("Average= %f S.D.=%f\n", average, sd);
return 0;
}
56 2. COMPONENTS OF C LANGUAGE
The output is
X x1 x2 x3 … xN
Y y1 y2 y3 … yN
(x3,y3)
y
|a x3+ b – y3|
y = a x+ b
(x1,y1)
|a x1+ b – y1| |a x2+ b – y2|
(x2,y2)
x
0 x1 x2 x3
The best fit line that represents the above data points in the format of
y D ax C b
is sought. The two parameters, a (slope) and b (intercept with the y axis), need to be
chosen to minimize an error. The error is defined as the difference between the measured
value and predicted value. Since this value can be either positive or negative, it is necessary
2.6. ARRAYS 57
to make it positive-definite by squaring the nominal value. Therefore, the total error,21 2
E ,
is the sum of the square of the difference at each point defined as
E2 .ax1 C b y1 /2 C .ax2 C b y2 /2 C : : : C .axN C b yN /2
XN
D .axi C b yi /2 : (2.8)
i D1
#include <stdio.h>
#define N 10
int main(){
float x[N]={1,2,3,4,5,6,7,8,9,10},
y[N]={-3, 2.9, 0.5, 3.0, 2.6, 5.2, 4.9, 4.5, 6.1, 7.2};
float xysum=0.0, xsum=0.0, ysum=0.0, x2sum=0.0;
float a, b, det;
int i;
for (i=0; i< N; i++)
{
xsum = xsum + x[i];
ysum = ysum + y[i];
xysum = xysum + x[i]*y[i];
x2sum = x2sum + x[i]*x[i];
}
det=x2sum*N - xsum*xsum;
a = (xysum*N-xsum*ysum)/det;
b = (x2sum*ysum-xysum*xsum)/det;
printf("The regression line is %f x + %f.\n", a, b);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
The regression line is 0.863636 x + -1.359998.
2.6.4 EXERCISES
1. Birthday paradox
How likely is it that two persons in a group of N people have the same birthday?23 Use
the Monte Carlo method to estimate the probability.
23 This problem is known as the birthday paradox and can be solved exactly by the probability theory. Mathematically, this
365Š
probability is expressed as p.N / D 1 365N .365 N /Š
. When N D 23, the probability is over 50%.
2.6. ARRAYS 59
Suggested Approach:
(a) Prepare an integer array, a[N], that holds birthday dates for N people.
(b) Generate a random number between 1 and 365 and assign the number to each ele-
ment of a[].24
(c) Compare a[0] with the rest of birthdays and if there is a match, get out of the loop,
increment the counter by 1 and go to (b) (the next round of simulation).
(d) Compare a[1] with the rest of birthdays and if there is a match, get out of the loop,
increment the counter by 1 and go to (b) (the next round of simulation).
(e) : : :.
(f ) After n simulations, compute the value of counter/n.
To exit from the loop, use the goto statement as
ExitLoop:;
.....
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
int main()
{
int i,a[10000];
float sum=0, avg, std;
srand(time(NULL));
24 Use the % operator. Example: 300%7 returns the remainder of 300 divided by 7, i.e., 6.
60 2. COMPONENTS OF C LANGUAGE
Notion Meaning
$ program > filename Output to file
$ program >> filename Append output to file
$ program < filename Get input from file
If a.out alone is entered from the keyboard, all the output from a.out is displayed
on the screen. However, with a.out > result.dat, the output is saved to an external file,
result.dat, and nothing is shown on the screen. You can examine the contents of result.dat
by the more command.
$ gcc prog.c
$ ./a.out > result.dat
$ more result.dat
If the program requires that the input must come from an existing external file and the output
must be saved to another external file, you can have both directions on the same line as
$ gcc prog.c
$ ./a.out < data.dat > result.dat
$ more result.dat
The file, data.dat, contains the necessary data to be input to the program.
The following command (in a DOS window) creates a file, filelist.dat, that lists all
the files in the current directory:26
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen("filename","w");
/*
Write something to fp.
*/
fclose(fp);
return 0;
}
The function, fopen(), takes a (append), w (write), or r (read) as a possible argument. The
following program opens an external file, data.dat, for writing and writes “Hello, World!”
to the file.
26 In the Windows system, a file, prn, cannot be used as the name for an external file. It is reserved for a printing device.
27 This is a FILE pointer that keeps track of the memory location of the file.
62 2. COMPONENTS OF C LANGUAGE
#include <stdio.h>
int main()
{
FILE *fp;
fp=fopen("data.dat","w");
fprintf(fp,"Hello, World!\n");
fclose(fp);
return 0;
}
The following program reads three floating numbers separated by a space from an external file,
data.dat, and prints out their values on the screen:
#include <stdio.h>
int main()
{
FILE *fp; float a,b,c;
fp=fopen("data.dat","r");
fscanf(fp,"%f %f %f", &a, &b, &c);
printf("%f %f %f", a,b,c);
fclose(fp);
return 0;
}
#include <stdio.h>
int main()
{
FILE *fp1, *fp2;
float a,b,c;
fp1=fopen("data1.dat","w");
fp2=fopen("data2.dat","w");
fprintf(fp1,"This is the first file.\n");
fprintf(fp2,"This is the second file.\n");
fclose(fp1); fclose(fp2);
return 0;
}
2.8. POINTERS 63
2.8 POINTERS
The concept of a pointer in C is probably the most challenging subject for a C learner. Pointers
are available in C and C++ but not in any other programming languages. Your program looks
just like what a C program should appear if pointers are used in many places.
However, there are only two new operators (& and *) that need to be learned in order to
understand the pointer. The good news for scientific and engineering programming is that you
can get around using a pointer for most of programming needs. The only instances that a pointer
is needed for engineering/science are (1) working on matrices and vectors in linear algebra and
(2) using a variable that is substituted for a function both of which will be explained in this
section.
#include <stdio.h>
int main()
{
float a =20.0, b=50.0;
float *pa, *pb;
pa=&a; pb=&b;
return 0;
}
When the compiler reads the program above, it will make a table of memory mapping which
may look like Table 2.8. Note that this is a fictitious machine for illustrative purposes.
In this fictitious machine, the variable a is mapped to the (absolute) memory location at
102 in RAM which holds the value of 20.0. Similarly, the variable b is mapped to the memory
location at 150 that holds the value of 50.0.
You can find out the memory location (address) that holds the value of a given variable
by placing an & (ampersand, called an address operator or a referencing operator) in front of the
variable name. Thus in the example above, a represents 20.0 and &a represents 102. Run the
following program:
#include <stdio.h>
int main()
64 2. COMPONENTS OF C LANGUAGE
Table 2.8: Memory map on a fictitious machine
{
int a=10;
printf("Address of a=%d.\n", &a);
return 0;
}
The compiler outputs a warning and the output from a.out is negative, which is wrong.
$ gcc prog.c
prog.c: In function 'main':
prog.c:5:10: warning: format '%d' expects argument of type 'int',
but argument 2 has type 'int *' [-Wformat=]
printf("Address of a=%d.\n", &a);
^
$ ./a.out
Address of a=-1074704200.
This is because &a holds the address of a memory location which is larger than the maximum
integer that can be handled by the compiler (=2147483647). The %p format instead of the %d
format should be used to display a memory address in hexadecimal mode28 correctly. Change
%d to %p in printf() in the previous code. The output will be something like (each machine is
different)
28 In hexadecimal format, 16 letters (0–9 and a–f ) are used to represent a number.
2.8. POINTERS 65
$ gcc prog.c
$ ./a.out
Address of a=0xbfa1e9a8.
The output from the two programs may look like (each machine is different)
In the first (left) program, the array, a[], is declared as an integer array while in the second
(right) program, a[] is declared as a double precision array.
In the output from the first (left) program, the address of adjacent components is separated
by 4 bytes which implies that the C compiler stores each integer number (int) using 4 bytes. On
the other hand, in the output from the second (right) program, the address is incremented by 8
bytes which implies that the C compiler stores each double precision (double) number using 8
bytes.
#include <stdio.h>
int main()
{
float a=20.0;
float *pa;
pa=&a;
printf("%p\n", pa);
printf("%p\n", &a);
return 0;
}
$ gcc prog.c
$ ./a.out
0xbfb0f214
0xbfb0f214
In the program above, float *pa declares that pa is a pointer pointing to a float variable.
Note that a pointer itself is always a large integer (memory address location) so the type of a
pointer (float in the example above) merely implies that the variable pointed by the pointer pa
is of float type. The pa=&a; statement means that the address of a is assigned to pa.
Sometimes within the program you want to examine what value the pointer actually refers
to, i.e., you want to know the content of the variable pointed by the pointer. Let’s look at the
following program:
#include <stdio.h>
int main()
{
float a=20.0;
float *pa;
pa=&a;
printf("%f\n", *pa);
printf("%f\n", a);
return 0;
}
The output is
2.8. POINTERS 67
$ gcc prog.c
$ ./a.out
20.000000
20.000000
In the program above, * (asterisk—known as the dereferencing operator) before a pointer vari-
able works the same way as using a directly. Therefore, if pa is a pointer pointing to a floating
variable a, the use of a and *pa within a program is identical. This way, you can effectively
change the content of a without directly mentioning a.
Pointers can be incremented or decremented just as any other variables. The difference
between the increment of pointers and the increment of regular variables is that the value of
increment for the pointer depends on the type of the variable the pointer is pointing to. Take
the following example:
#include <stdio.h>
int main()
{
float a[3]={1.0, 2.0, 3.0}, *pa=&a[0];
double b[3]={1.2345670, 2.009876555, 3.14159265}, *pb=&b[0];
printf("float %15p%15p%15p\n", pa, pa+1, pa+2);
printf("double %15p%15p%15p\n", pb, pb+1, pb+2);
return 0;
}
$ gcc prog.c
$ ./a.out
float 0xbf8135e4 0xbf8135e8 0xbf8135ec
double 0xbf8135f0 0xbf8135f8 0xbf813600
In the program above, as a double precision variable occupies more memory space (8 bytes) than
a single precision variable (4 bytes), the increment of the double precision pointer, pb, advances
the memory location by 8 bytes while the increment of the single precision pointer, pa, advances
the memory location by 4 bytes even though the increment for both pointers is 1.
The C language uses pointers extensively for the following reasons:
• The only way to modify the content of arguments in a function call is to use pointers.
• Computer hardware can be directly controlled by pointers.
• Matrices and vectors in linear algebra are actually pointers.
68 2. COMPONENTS OF C LANGUAGE
2.8.3 FUNCTION ARGUMENTS AND POINTERS
One of the usages of pointers is to modify the content of a variable (parameter) passed through
a function call. Suppose you want to write a function, tentimes(), that accepts a variable, a, as
a parameter and multiply 10 by a. Such a program may look like
#include <stdio.h>
void tentimes(float a)
{
a = 10.0*a;
}
int main()
{
float b=20;
tentimes(b);
printf(" b = %f\n", b);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
b = 20.000000
Unfortunately, this program does not work as intended. The content of b was not modified even
with the a = 10.0*a statement in the definition of tentimes().
There is nothing wrong with this program as this is how a function call in C works. When
a function is called with an argument (i.e., tentimes(b)), a copy of the value of the argument
(i.e., b) is made, that value is passed to the function and the actual argument variable b is never
altered. All that the function (i.e., tentimes()) can see from the function main() is the copied
value of the parameter (i.e., 20) and this information does not have anything to do with the
variable itself (i.e., b). This effectively makes it impossible to modify the value of arguments
passed to functions. This way of passing a parameter in C functions is called the call by value
method.
A fix is to use pointers. Instead of passing a copy of the value of the variable to the function,
if the address of that variable is passed to the function, the function can find where the value
of the variable is stored, go to that address, and modify the content at that address any way it
wants. This is called the call by reference method. The program above can be now modified as
2.8. POINTERS 69
#include <stdio.h>
void tentimes(float *a)
{
*a = 10.0**a;
}
int main()
{
float b=20;
tentimes(&b);
printf(" b = %f\n", b);
return 0;
}
$ gcc prog.c
$ ./a.out
b = 200.000000
This output is what was expected. Note that the dummy variable, a, is declared as a pointer (*a)
and instead of b, the address of b (&b) is passed to the function, tentimes(). In the function,
tentimes(), *a represents the content of the variable pointed by a.29
As an example of this concept, the following program uses a function, swap(), that takes
two pointers as arguments and exchanges the values of the two variables pointed by the pointers:
#include <stdio.h>
void swap(float *pa, float *pb)
{
float tmp;
tmp=*pa;
*pa=*pb;
*pb=tmp;
}
int main()
{
float a=10.0, b=50.0;
printf("Old a = %f and old b = %f\n",a,b);
swap(&a,&b);
29 10.0**a is the product between 10.0 and the value pointed by a, i.e., *a.
70 2. COMPONENTS OF C LANGUAGE
The output is
$ gcc prog.c
$ ./a.out
Old a = 10.000000 and old b = 50.000000
New a = 50.000000 and new b = 10.000000
#include <stdio.h>
int main()
{
float a[3]={1.0, 2.0, 3.0};
return 0;
}
the C compiler actually interprets a as a pointer and reserves appropriate memory space. In the
program above, an array a is a pointer pointing to the 0-th element of the array, a[0], while
a[0], a[1], and a[2] behave just like regular variables. The content of a is the address which
points to a[0]. Since a is a pointer, dereferencing the array name (*a) will give the 0-th element
of the array, i.e., a[0]. This gives us a range of equivalent notations for accessing arrays.
In Table 2.9, *(a+2) means that the value (address) of the pointer, a, is advanced by two
units and the content at that address is referenced which is equivalent to the value of a[2].
#include <stdio.h>
void twice(float *a)
{
int i;
for (i=0; i<3; i++) a[i]=2*a[i];
}
int main()
{
float b[3]={1.0, 2.0, 3.0};
int i;
twice(b);
for (i=0; i<3; i++) printf("%f\n", b[i]);
return 0;
}
$ gcc prog.c
$ ./a.out
2.000000
4.000000
6.000000
The program above is to use a function that takes an array as an input and doubles all the
elements in that array. Previously, it was noted that the only way to modify the argument in
a function is to use a pointer. This principle also works for arrays as the name of an array is a
pointer. Therefore, when passing an array to a function, the address operator, &, before the array
name is not needed. The following program does the same as the one above:
#include <stdio.h>
void twice(float a[3])
{
int i;
for (i=0; i<3; i++) a[i]=2*a[i];
}
int main()
72 2. COMPONENTS OF C LANGUAGE
{
float b[3]={1.0, 2.0, 3.0};
int i;
twice(b);
for (i=0; i<3; i++) printf("%f\n", b[i]);
return 0;
}
type_of_function (*func_name)(type_of_argument)
where type_of_function is the type of a function to which the function points, func_name
is the name of the function pointer and type_of_argument is the type of the argument in
func_name. For example, a function pointer, float (*foo)(float, float), can be pointed
to an actual function, float f1(float x, float y).
In the following code, func() is a function pointer which points to an actual double type
function that has a double type variable as the argument.
#include <stdio.h>
#include <math.h>
double f1(double x)
{return x ; }
double f2(double x)
30 This is similar to an array. The array name itself is a pointer pointing to the address of the first element of the array.
2.8. POINTERS 73
{return x*x ; }
int main()
{
double (*func)(double);
func=&f1;
printf("%lf\n", func(2)) ;
func=&f2;
printf("%lf\n", func(2));
func=&cos;
printf("%lf\n", func(3.141));
return 0;
}
The output is
As func() is a function pointer, a statement such as func=&cos assigns the address of the cosine
function defined in <math.h> to func. After this statement, func() and cos() are identical.
2.8.6 SUMMARY
• The asterisk (*) in C has the following meanings:
2.8.7 EXERCISES
1. We want to write a function, circle, which takes the radius of a circle from the main
function and assign the area of the circle to the variable, area, and the perimeter of the
circle to the variable, perimeter. Since the contents of the variables are to be modified by
a function, it is necessary to use pointers. Use the following template and complete your
program.
#include <stdio.h>
void circle(float r, (fill in your code))
{
(fill in your code...);
}
int main()
{
float r, area, perimeter;
printf("Enter radius = "); scanf("%f", &r);
circle(r, &area, &perimeter);
printf("r=%f area=%f peri=%f\n", r, area, perimeter);
return 0;
}
2. Write a function that takes two floating variables, a and b , and rearrange them in ascending
order, i.e.,
#include <stdio.h>
void reorder(float *pa, float *pb)
{
(your code here)
}
int main()
{
float a=15, b=-6;
reorder(&a, &b);
2.9. STRING MANIPULATION 75
shows
-6 15
#include <stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
int i;
for (i=0;i < 5;i++) printf("%d\n", a[i]);
for (i=0;i < 5;i++) printf("%d\n", *(a+i));
return 0;
}
so a[i] and *(a+i) are identical. Using this idea, write a program to compute the average
of all the elements for the following array:
In the left program above, the float variable, a, represents a single value, 2:0. In the right
program above, the char variable, c, represents a single character, A.
In the left programs above, an array, a, represents a set of four numbers, 2.0, 3.0, 4.0,
5.0 and the first number is printed. In the right programs above, an array, b, represents a string
of six characters, “Hello!,” and the first character is printed.
In the left program above, a pointer variable, a, points to the address of a[0]. In the right
program, a pointer variable, a, points to the address of the first character, “H.” Instead of using
b[ ]={'H', 'E', 'L', 'L', 'O', '!', '\0'}, a direct assignment of b[ ]="HELLO!" can
be used with the double quotation mark ("). Note that a special character '\0' needs to be
placed to mark the end of the string when we initialize each character individually.
Use the %s format to represent the entire string instead of the %c format that represents
only one character.
2.9. STRING MANIPULATION 77
#include <stdio.h>
int main()
{
char *a;
a="Hello, World!";
printf("%s\n",a);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Hello, World!
As is seen in the examples above, a single quotation mark (') and a double quotation mark (")
work differently. The single quotation mark must be used for one character while the double
quotation mark must be used for a string of characters. For example, "ABC" (double quotation)
is for a string of characters and is therefore an array (pointer). On the other hand, 'A' (single
quotation) is for a single character.
Consider the following program:
#include <stdio.h>
int main()
{
char s[4] = "ABC";
printf("%s\n", s);
return 0;
}
You may wonder why the element number of the array, s, is 4, not 3. The C compiler automat-
ically adds a special character NULL (ASCII code 0, commonly denoted as “n0”) to the end of
the string to indicate that that is the end of the character array so that the element number of a
character array is always the number of characters plus 1.
To read a string from the standard input (i.e., keyboard), use the following example:
#include <stdio.h>
int main()
{
78 2. COMPONENTS OF C LANGUAGE
char str[100];
printf("Enter a word = ");
scanf("%s", str);
printf("%s\n",str);
return 0;
}
$ gcc prog.c
$ ./a.out
Enter a word = Good morning
Good
Note that there is no “&” before str in the scanf() function as str is already a pointer. Also,
only “Good” is printed even though “Good morning” was entered. This is because the format,
%s, in scanf(), reads input until a space is entered (a word). If two strings (two words) are to
be read, "%s %s" must be used. The C compiler automatically adds “\0” after the end of the last
character in the string.
#include <stdio.h>
#include <string.h>
int main()
{
char c1[] = "ABCDE", c2[6];
strcpy(c2,c1);
printf("%s\n",c2);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
ABCDE
2.9. STRING MANIPULATION 79
In the program above, the function, strcpy(c2,c1), copies the pointer, c1, to another pointer,
c2. Note c2[6] instead of c2[5] as the NULL character must be added after the end of the
string.
To compare two strings, use strcmp() available in <string.h>:
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
printf("Enter \"ABCDEF\"");
scanf("%s", s);
if (strcmp(s,"ABCDEF") == 0) printf("ABCDEF was entered correctly.\n");
else printf("Wrong. %s was entered.\n",s);
return 0;
}
In the program above, the strcmp() function takes two strings as the arguments and returns 0
if the two strings match. Note that you can output " (double quotation mark) by “escaping” it
using the backslash character.
To find the length of the string, use the strlen() function:
#include <stdio.h>
#include <string.h>
int main()
{
char c[50];
printf("Enter string = ");
scanf("%s", c);
printf("You entered %s\n", c);
printf("Its length is %d\n", strlen(c));
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter string = Good afternoon.
80 2. COMPONENTS OF C LANGUAGE
Again, only “Good” was read as the format, %s, reads a string until a space is entered (a word).
Instead of entering necessary information during the interactive session (using scanf() and
printf() functions), you can enter necessary parameters at the same time you enter the program
name as
This is called “command line arguments” (also called “command line parameters”) and provides
a handy way to pass necessary arguments to the main() function without user interaction.
Recall that the function, main(), is the function in C that is to be executed first. Other
than that, it is an ordinary function in C just like any other functions so that it must have an
argument part. The function, main(), actually takes two arguments. The first argument is the
number of command line arguments including the program name itself and the second argument
(an array of strings) stores each command line argument entered after the program name. The
syntax of the arguments in main() is
The first argument, argc, is of integer type and is assigned the number of command line argu-
ments including the command name itself. The second argument, argv, is a pointer to an array
of strings that stores each of the command line arguments. Note that argv[ ] is an array so that
it can take multiple command line arguments.31
31 Actually, argv[ ] is a pointer to another pointer (an array of another array) as each element of argv[ ] is a string of characters.
2.10. COMMAND LINE ARGUMENTS 81
Consider the following program:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
printf("Number of arguments = %d\n", argc);
for(i=0; i<argc; i++) printf("%d: %s\n", i, argv[i]);
return 0;
}
Execute the program above with command line arguments as in the following example:
$ gcc prog.c
$ ./a.out I hate C language.
Number of arguments = 5
0: ./a.out
1: I
2: hate
3: C
4: language.
The string “./a.out” is stored in argv[0], the string “I” is stored in argv[1], etc.
Note that each of the command line arguments is entered as a string. For example, when
a number 4 is entered, it is stored as a character “4” (ASCII code 52), not as the numeric value
of 4. If you want the program to interpret the entered parameters as numeric values, not a string
of characters, use atoi() (ASCII to INTEGER) or atof() (ASCII to FLOAT) available in
<stdlib.h>.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("%d\n", atoi(argv[1]));
return 0;
}
$ gcc prog.c
$ ./a.out 2018
2018
The following program computes the sum of all the numbers entered as command line
arguments:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
float sum=0.0; int i;
for (i=1;i<argc;i++) sum=sum+atof(argv[i]);
printf("The sum is %f.\n" , sum);
return 0;
}
$ gcc prog.c
$ ./a.out 1 2 3 4 5 6 7 8 9 10
The sum is 55.000000.
2.10.2 EXERCISES
1. Write a program using the concept of command line arguments to solve a quadratic equa-
tion, ax 2 C bx C c D 0, by entering a, b , and c as command line arguments, i.e.,
$ ./a.out 3 -1 -1
will return
by solving 3x 2 x 1 D 0.
2.11. STRUCTURES 83
2.11 STRUCTURES
2.11.1 MIXTURE OF DIFFERENT TYPES OF VARIABLES
An array is a single variable that can represent many elements. However, all the elements in
an array must be of the same type. What if you want to have a single variable that represents
different types of elements such as a mixture of integers, floating numbers and strings?
A structure is a collection of one or more variables under a single name. These variables can
be of different types, and are selected from the structure by name. A structure is a convenient
way of grouping several pieces of related information together.
For example, a structure called student can be created which represents the school records
of students such as the ID, the midterm score, the final score and the final grade. The following
program exemplifies the concept of structures:
#include <stdio.h>
struct student{
char *ID;
int Midterm;
int Final;
char Grade;
};
int main()
{
struct student smith={"1000123456", 89, 98, 'A'},
doe={"1000123457", 45, 53, 'F'};
printf("%s\n", smith.ID);
printf("%d\n", doe.Midterm);
doe.Grade='D';
printf("%c\n", doe.Grade);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
1000123456
45
D
84 2. COMPONENTS OF C LANGUAGE
In the program above, a structure called student is defined having four members (ID, Midterm,
Final, Grade) which is a mixture of different types. The first member, ID is a string (hence, a
pointer), the second and third members, Midterm and Final, are integers and the last mem-
ber, Grade, is a character. Two variables, smith and doe, are declared as of student type and
initialized. A member in a structure can be accessed by using the dot (.).
You can also define an array of structures as
#include <stdio.h>
struct student{
char *ID;
int Midterm;
int Final;
char Grade;
};
int main()
{
struct student myclass[15];
int i;
myclass[0].ID="10000123212";
myclass[0].Grade='C';
(.....)
myclass[14].Grade='B';
(.....)
return 0;
}
#include <stdio.h>
struct student{
char *ID;
int Midterm;
int Final;
char Grade;
};
int main()
{
struct student Smith={"David Smith", 12, 45, 'F'}, *ptr;
2.11. STRUCTURES 85
ptr = &Smith;
/*
..................
*/
#include <stdio.h>
typedef struct {
char *ID;
int Midterm;
int Final;
char Grade;
} student;
int main()
{
student Jones={"Jones", 12, 45, 'F'}, *ptr;
ptr = &Jones;
/*
..................
*/
printf("%s\n", ptr->ID);
return 0;
}
The concept of structure is extended to the concept of class which plays an essential
role in C++ (and Java).
One of useful applications of structure in scientific/engineering computation is complex
numbers. The C language does not support complex numbers32 but it is easy to implement
32 C++ has a complex number class.
86 2. COMPONENTS OF C LANGUAGE
complex numbers using structures. The following program defines a complex type (a C bi ) and
computes addition of two complex numbers:
#include <stdio.h>
typedef struct
{float Real; float Im;} Complex;
Complex ComplexAdd(Complex z1, Complex z2)
{
Complex z;
z.Real = z1.Real + z2.Real;
z.Im = z1.Im + z2.Im;
return z;
}
int main()
{
Complex z1, z2, z;
printf("Enter real and imaginary parts of z1 separated by space = ");
scanf("%f %f", &z1.Real, &z1.Im);
printf("Enter real and imaginary parts of z2 separated by space = ");
scanf("%f %f", &z2.Real, &z2.Im);
z = ComplexAdd(z1, z2);
printf("%f + %f I \n", z.Real, z.Im);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
Enter real and imaginary parts of z1 separated by space = 2 3
Enter real and imaginary parts of z2 separated by space = -1 4
1.000000 + 7.000000 I
Using typedef, the structure, Complex, behaves just like int or float and variables can be
declared using Complex as Complex z1, z2;.
2.11.2 EXERCISES
1. Following the last example above, write a program to do complex division between two
complex numbers, i.e., z1 =z2 . Using the program, compute z1 =z2 where z1 D 2:12 C 1:21i
and z2 D 2:8 C 7:8i .
2.11. STRUCTURES 87
As a template, the following program computes the product of two complex numbers:
#include <stdio.h>
typedef struct
{float Real; float Im;} Complex;
Complex ComplexMultiply(Complex z1, Complex z2)
{
Complex z;
z.Real = z1.Real*z2.Real - z1.Im*z2.Im;
z.Im = z1.Real*z2.Im + z1.Im*z2.Real;
return z;
}
int main()
{
Complex z1, z2, z;
z1.Real=0.25; z1.Im=-3.1412;
z2.Real=0.98; z2.Im=1.655;
z=ComplexMultiply(z1,z2);
printf("The product of z1 * z2 = %f + %f I.\n",
z.Real, z.Im);
return 0;
}
The output is
$ gcc prog.c
$ ./a.out
The product of z1 * z2 = 5.443686 + -2.664626 I.
PART II
Numerical Analysis
91
Now that the basic syntax of the C language has been explained, you are ready to write C pro-
grams to solve many problems arising in engineering and science. In Part II, numerical meth-
ods for solving nonlinear equations, a set of simultaneous equations and ordinary differential
equations as well as numerically differentiating and integrating given functions are discussed.
Solving these equations analytically requires advanced levels of mathematics. However, solving
equations numerically often only involves intuitive or visual interpretation and not necessarily
requires higher mathematics.
Although all the essential topics in numerical analysis are elucidated, it is not possible to
cover every single aspect of numerical analysis. For a comprehensive reference, Numerical Recipes
in C 33 is suggested.
CHAPTER 3
1.
#include <stdio.h>
int main()
{
float s=0.0;int i;
for (i=0;i <10000;i++) s=s+0.1;
printf("%f\n",s);
return 0;
}
The intention of the program is to add 0:1 for 10;000 times. The result should be 1;000.
However, the program outputs the following result:
$ gcc prog.c
$ ./a.out
999.902893
The output is not 1,000 but 999:902893 which is almost 1,000 but when precision is criti-
cal, this result is not acceptable. The error in this example comes from conversion between
decimal numbers and binary numbers. The decimal numbers in the source code are con-
verted to the binary numbers with a possibility of conversion error and the binary numbers
are converted back to the decimal numbers adding another conversion error.1
1 Forexample, conversion of decimal 0.1 to binary is a recurring binary 0:010011001100 : : : and conversion of binary
0:0001100110011001100 to decimal is 0:0999985.
94 3. NOTE ON NUMERICAL ERRORS
2.
#include <stdio.h>
int main()
{
float a,b,c;
a=123.45678;
b=123.45655;
printf("%f\n",a-b);
return 0;
}
As this program subtracts 123.45655 from 123.45678, the result should be 0.00023. How-
ever, the output from the program is not what it is supposed to be.
$ gcc prog.c
$ ./a.out
0.000229
The output is not 0.00023 but 0.000229. The error may seem small but again if precision
is required, this is not acceptable. The error in this code comes from subtracting a number
from another number which is so close resulting in the loss of the significant figures (also
called a cancellation error).
Both types of errors are inevitable and there is no way to completely eliminate such er-
rors. However, possible harm can be minimized by using double instead of float for floating
numbers. When a number is declared as double, it is assigned 8 bytes and effectively increases
the valid range. While the range of a float variable is ˙10 38 1038 with seven significant
digits, the range of a double variable is ˙10 308 19308 with 15 significant digits.
In the previous programs, change float to double and also change %f to %lf (long float)
in the printf() function.
1.
#include <stdio.h>
int main()
{
double s=0.0;int i;
for (i=0;i<10000;i++) s=s+0.1;
printf("%lf\n",s);
95
return 0;
}
$ gcc prog.c
$ ./a.out
1000.000000
2.
#include <stdio.h>
int main()
{
double a,b,c;
a=123.45678;
b=123.45655;
printf("%lf\n",a-b);
return 0;
}
$ gcc prog.c
$ ./a.out
0.000230
Another example of cancellation error is found in the innocent looking quadratic equation ex-
pressed as
ax 2 C bx C c D 0;
whose two roots are given as
p
b˙ D p
xD ; DD b2 4ac: (3.1)
2a
Consider this seemingly trivial equation
x 2 C 200000x 3 D 0;
where the exact solutions are
x1 D 200000; x2 D 0:000015:
The coding for this equation is straightforward as
96 3. NOTE ON NUMERICAL ERRORS
#include <stdio.h>
#include <math.h>
int main()
{
float a, b, c, disc,x1, x2;
a=1.0;b=200000;c=-3;
disc=b*b-4*a*c;
x1=(-b-sqrt(disc))/(2*a);
x2=(-b+sqrt(disc))/(2*a);
printf("x1 = %f, x2 = %f\n",x1,x2);
return 0;
}
The output is
On the
p other hand, b D 200000:0: Therefore, a cancellation error occurs when b is subtracted
from D as they are so close. Again, this can be avoided by using double as
#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, disc,x1, x2;
a=1.0;b=200000;c=-3;
disc=b*b-4*a*c;
x1=(-b-sqrt(disc))/(2*a);
x2=(-b+sqrt(disc))/(2*a);
printf("x1 = %lf, x2 = %lf\n",x1,x2);
return 0;
}
97
The output is
In numerical analysis, do not use float but use double exclusively. As a variable declared as
double occupies double the memory space (8 bytes) of a float variable (4 bytes), the size of
the resulting executable increases but that’s a small price to pay. If infinite precision is desirable,
symbolic capable systems such as Mathematica2 and Maple should be used.
CHAPTER 4
Roots of f .x/ D 0
In this chapter, numerical solutions for a single equation, f .x/ D 0, are sought. The function,
f .x/, can be a polynomial function or any nonlinear function of x .
The fundamental theorem of algebra states that an n-th order polynomial equation has n
roots including complex roots. This does not mean that all the roots for polynomial equations
can be obtained analytically in closed form. In fact, a fifth-order polynomial equation and beyond
has no formula for their roots in closed form.1
Two important algorithms to numerically solve a single equation, f .x/ D 0, are explained
in this chapter. They are (1) the bisection method and (2) Newton’s method. The bisection
method is guaranteed to obtain at least one root while Newton’s method provides a faster algo-
rithm to obtain roots.
4. Else set x1 x3 .
1 This theorem known as the Galois theory was proven by a French mathematician, Évariste Galois (1811–1832), pronounced
as gal-wa, when he was 19.
100 4. ROOTS OF f .x/ D 0
y
f (x) f (x2)
x1 x4
x
0 x3 x2
f (x1)
double f(double x)
{
4.1. BISECTION METHOD 101
return pow(x,2)-2;
}
/* start of main */
int main()
{
double x1, x2, x3;
int count;
do
{
printf("Enter xleft and xright separated by space =");
scanf("%lf %lf", &x1, &x2);
}
while (f(x1)*f(x2)>0);
/* bisection start */
for (count=0;count< N; count++)
{
x3= (x1+x2)/2.0;
if (f(x1)*f(x3)<0 ) x2=x3; else x1=x3;
if ( f(x3)==0.0 || fabs(x1-x2)< EPS ) break;
}
printf("iteration = %d\n", count);
printf("x= %lf\n", x1);
return 0;
}
The program prompts the user to enter two points (x1 and x2 ) and if f .x1 /f .x2 / > 0, the user is
prompted again until f .x1 /f .x2 / < 0 is satisfied. Note the usage of the do{...} while{...}
statement. The function, fabs(), available in <math.h> returns the absolute value of the argu-
ment. The output looks like
Typically, the bisection method converges after 30–40 iterations for most equations. To provide
x1 and x2 as an initial guess, it is important to draw a rough graph of f .x/ with a graphical
102 4. ROOTS OF f .x/ D 0
application such as gnuplot (see Appendix A) to estimate an approximate interval in which a
root is located. Although the bisection method is not the fastest method available, it guaranteers
that at least one root can be obtained if the initial interval is chosen correctly.
f (x)
x2 x3
x
0 x1
From Figure 4.4, the equation of a straight line that passes .a; b/ with a slope of m is
expressed as
y b D m.x a/:
Therefore, the tangent line that passes .x1 ; f .x1 // with the slope of f 0 .x1 / is expressed as
y f .x1 / D f 0 .x1 /.x x1 /:
The condition that this line intercepts with the x axis is
0 f .x1 / D f 0 .x1 /.x x1 /;
which can be solved for x as
f .x1 /
x D x1 :
f 0 .x1 /
4.2. NEWTON’S METHOD 103
y – b = m (x – a)
b m (slope)
(a,b)
x
0 a
x1 D 2;
f .2/ 2
x2 D 2 0
D2 D 1:5;
f .2/ 4
f .1:5/ 0:25
x3 D 1:5 0
D 1:5 D 1:41667;
f .1:5/ 3
f .1:4167/
x4 D 1:4167 D : : : D 1:4142:
f 0 .1:4167/
As is seen above, the convergence is attained after only four iterations.
Here is the algorithm for Newton’s method:
104 4. ROOTS OF f .x/ D 0
1. Pick initial guess, x1 .
2. Confirm that f 0 .x1 / ¤ 0.
3. Repeat
(a) x2 x1 f .x1 /=f 0 .x1 /
(b) x1 x2
4. Until jx1 x2 j .
Note that Newton’s method fails when f 0 .xn / is zero which makes the denominator in Eq. (4.1)
zero.
A C program for Newton’s method is shown below:
#include <stdio.h>
#include <math.h>
#define EPS 1.0e-10
double f(double x)
{
return x*x-2;
}
double fp(double x)
{
return 2*x;
}
double newton(double x)
{
return x - f(x)/fp(x);
}
int main()
{
double x1, x2;
int i;
do{printf("Enter initial guess =");
scanf("%lf", &x1);}
while (fp(x1)==0.0) ;
for (i=0;i<100;i++)
{
x2=newton(x1);
4.2. NEWTON’S METHOD 105
As is seen in this example, the number of iterations until convergence is 4, much less than the
bisection method.
p
As a side note, the square root of a (D a) can be approximated by solving f .x/ D x 2 a.
Using Newton’s method, the following relation can be derived:
xn2 a
xnC1 D xn
2xn
1 a
D xn C :
2 xn
p p
This iteration scheme can be used to obtain a even by hand. For example, for 3 D 1:732 : : :
1 3 1 3 1 3
x1 D 1; x2 D 1C D 2; x3 D 2C D 1:75; x4 D 1:75 C D 1:732:
2 1 2 2 2 1:75
f .x; y/ D 0;
g.x; y/ D 0:
By expanding each of the above by the Taylor series for two variable functions, one obtains
@f ˇˇ @f ˇˇ
f .x; y/ f .x0 ; y0 / C .x x0 / C .y y0 /; (4.2)
@x .x0 ;y0 / @y .x0 ;y0 /
@g ˇˇ @g ˇˇ
g.x; y/ g.x0 ; y0 / C .x x0 / C .y y0 /: (4.3)
@x .x0 ;y0 / @y .x0 ;y0 /
If .x; y/ satisfies
f .x; y/ D 0; g.x; y/ D 0;
Equations (4.2)–(4.3) can be written as
!
@f @f
0 f .x0 ; y0 / @x
; @y x x0
D C @g @g ˇ ;
0 g.x0 ; y0 / @x
; @y ˇ.x0 ;y0 / y y0
or in vector-matrix form as
0 D f.x0 ; y0 / C J.x xo /; (4.4)
where
!
@f @f
@x
; @y f .x0 ; y0 / x x0
J @g @g ˇ ; f.x0 ; y0 / D ; x xo D :
@x
; @y ˇ.x0 ;y0 / g.x0 ; y0 / y y0
The matrix, J , is called the Jacobian matrix. Equation (4.4) can be solved for x as
1
x D xo J f.xo /; (4.5)
1
where J is the inverse matrix of J . Equation (4.5) is the 2-D version of Eq. (4.1).
Example
Numerically solve the following two simultaneous equations for .x; y/:
1
x 3 C y 2 D 1; xy D :
2
2 This topic can be skipped.
4.2. NEWTON’S METHOD 107
(Solution) Let
1
f x3 C y2 1; g xy :
2
It follows
3x 2 ; 2y
J D ;
y; x
and !
x 2y
1 3x 3 2y 2
; 3x 3 2y 2
J D y 3x 2 ;
3x 3 2y 2
; 3x 3 2y 2
therefore,
! 0 1
x 2y x 4 x .y 2 C1/Cy
3x 3 2y 2
; 3x 3 2y 2
3
x Cy 1 2
J 1
fD y 3x 2 D@ 3x 3 2y 2
4x 3 y 3x 2 2y 3 C2y
A:
; xy 1=2
3x 3 2y 2 3x 3 2y 2 6x 3 4y 2
#include <stdio.h>
#include <math.h>
int main()
{
double x=1.0, y=1.0;
int i,n;
printf("Enter x, y and # of iterations=");
scanf("%lf %lf %d", &x, &y, &n);
for (i=0;i<=n;i++)
{
x = x -(pow(x,4) + y - x*(1 + y*y))/(3*pow(x,3) - 2*y*y);
y = y -(-3*x*x + 2*y + 4*pow(x,3)*y - 2*pow(y,3))/
(6*pow(x,3) - 4*y*y);
}
printf("%lf %lf\n", x, y);
return 0;
}
108 4. ROOTS OF f .x/ D 0
The output looks like
Starting .x; y/ D .1:0; 1:0/, convergence was reached at .x; y/ D .0:877275; 0:569947/ after
only 4 iterations. Note that this is just one of multiple roots. It is necessary to try different
initial guess to obtain other roots.
4.2.3 EXERCISES
1. Find all the roots for
ex 3x D 0;
using the bisection method.
2. Find x for
x sin x D e x x sin x 2 ;
by Newton’s method in the interval Œ 2; 2.
109
CHAPTER 5
Numerical Differentiation
5.1 INTRODUCTION
It is always possible to analytically differentiate a given function no matter how lengthy or com-
plicated it may be as long as the function is given explicitly. Computer algebra systems such as
Mathematica1 and Wolfram Alpha2 can also differentiate any analytical function exactly.
The only occasion in which numerical differentiation is needed is when a function is given
numerically. Consider Table 5.1 that defines f .x/ numerically.
x f (x)
1.0 1.0
1.5 3.375
2.0 8.0
2.5 15.625
The graph of f .x/ is shown in Figure 5.1. Our goal is to find f 0 .x/ for each x in the
table in terms of difference. Graphically, differentiation is equivalent to the slope (the rate of
change). For example, in order to approximate f 0 .2:0/, if one compares f .2:0/ with f .2:5/, the
rate of change is .f .2:5/ f .2:0//=0:5/ D 15:25 and if one compares f .2:0/ with f .1:5/, the
rate of change is .f .2:0/ f .1:5//=0:5/ D 9:25. The difference between the two approximations
is large and neither one can serve as a good approximation to f 0 .2:0/.
• Forward difference
1 Wolfram, The Mathematica Book, Version 4, Cambridge University Press, 1999.
2 www.wolframalpha.com
110 5. NUMERICAL DIFFERENTIATION
15
10 Slope = 15.25
Slope = 9.25
5
1 2 3 4
h2 00 h3
f .x C h/ D f .x/ C hf 0 .x/ C f .x/ C f 000
.x/ C : : :
0
2Š 3Š
f .x/ C hf .x/: (5.1)
By retaining the first two terms of the right-hand side of Eq. (5.1), f 0 .x/ can be expressed
as
f .x C h/ f .x/
f 0 .x/ : (5.2)
h
This is called the forward difference scheme. Using Eq. (5.2), f 0 .2/ in Table 5.1 is approxi-
mated as .f .2:5/ f .2:0//=0:5/ D 15:25.
• Backward difference
The backward difference scheme can be obtained by replacing h in Eq. (5.1) by h as
h2 00 h3
f .x h/ D f .x/ hf 0 .x/ C f .x/ f 000
.x/ C : : :
0
2Š 3Š
f .x/ hf .x/; (5.3)
From Eq. (5.3), f 0 .x/ can be expressed as
f .x/ f .x h/
f 0 .x/ : (5.4)
h
This is called the backward difference scheme. Using Eq. (5.4), f 0 .2/ in Table 5.1 is approx-
imated as .f .2:0/ f .1:5//=0:5/ D 9:25.
5.2. FORWARD/BACKWARD/CENTRAL DIFFERENCE 111
• Central difference
Equations (5.1) and (5.3) are listed again as
h2 00 h3
f .x C h/ D f .x/ C hf 0 .x/ C f .x/ C f 000 .x/ C : : : (5.5)
2Š 3Š
0 h2 00 h3 000
f .x h/ D f .x/ hf .x/ C f .x/ f .x/ C : : : (5.6)
2Š 3Š
Subtracting Eq. (5.6) from Eq. (5.5) yields
h3
f .x C h/ f .x h/ D 2hf 0 .x/ C 2 f 000
.x/ C : : :
3Š
Dropping the second term and beyond, f 0 .x/ can be expressed as
f .x C h/ f .x h/
f 0 .x/ : (5.7)
2h
Equation (5.7) is called the central difference scheme.
By using Eq. (5.7), f 0 .2/ in Table 5.1 is approximated as
f .2:5/ f .1:5/
f 0 .2/ D 12:25:
2 0:5
Revealing that f .x/ used in Table 5.1 is f .x/ D x 3 , it follows that f 0 .x/ D 3x 2 and hence
f 0 .2/ D 3 22 D 12. It is seen from the above that the central difference yields the best approx-
imation as the truncation error is in the order of h2 while the truncation error for the forward
and backward difference methods is in the order of h.
If the second-order derivative of f .x/3 is desired, adding Eqs. (5.5) and (5.6) yields
f .x C h/ C f .x h/ D 2f .x/ C h2 f 00 .x/ C : : :
EXAMPLE
Table 5.2 shows numerical values for f .x/ (numerical values of sin x from x D 0:0–1:0).
The following code implements the central difference scheme:
3 If f .x/ represents a position at time, x , f 00 .x/ is its acceleration.
112 5. NUMERICAL DIFFERENTIATION
Table 5.2: Example of numerical differentiation
#include <stdio.h>
#define N 11
int main()
{
double y[N]={0, 0.0998, 0.1986, 0.2955, 0.3894, 0.4794, 0.5646,
0.6442, 0.7173, 0.7833, 0.8414};
double central[N], h=0.1;
int i;
for (i=1;i<N-1;i++) central[i]= (y[i+1]-y[i-1])/(2*h);
printf (" x Central \n---------------------------\n");
for (i=1;i<N-1;i++) printf ("%lf %lf\n", i*h, central[i]);
return 0;
}
The output is
$ gcc central.c
$ ./a.out
x Central
---------------------------
0.100000 0.993000
0.200000 0.978500
0.300000 0.954000
0.400000 0.919500
0.500000 0.876000
0.600000 0.824000
0.700000 0.763500
0.800000 0.695500
0.900000 0.620500
5.2. FORWARD/BACKWARD/CENTRAL DIFFERENCE 113
The central difference scheme is more accurate than the forward difference scheme and the
backward difference scheme. However, as seen in the output above, the central difference scheme
cannot compute f 0 .0:0/ and f 0 .1:0/ as f . 0:1/ and f .1:1/ are not available. Using the forward
difference scheme for f 0 .0:1/ or the backward difference scheme for f .1:0/ is poor compromise.
There is a way to approximate f 0 .0:0/ and f 0 .1:0/ with the same accuracy as the central
difference scheme. Replacing h in Eq. (5.6) by 2h yields
4h2 00
f .x 2h/ D f .x/ 2hf 0 .x/ C f .x/ C : : : (5.9)
2Š
The h2 term in Eq. (5.9) can be eliminated by subtracting Eq. (5.9) from 4 times of Eq. (5.6) as
#include <stdio.h>
#define N 11
int main()
{
double y[N]={0, 0.0998, 0.1986, 0.2955, 0.3894, 0.4794, 0.5646,
0.6442, 0.7173, 0.7833, 0.8414};
double central[N], h=0.1;
int i;
for (i=1;i<N-1;i++) central[i]= (y[i+1]-y[i-1])/(2*h);
central[10]=(3*y[10]-4*y[9]+y[8])/(2*h);
printf (" x Central \n---------------------------\n");
for (i=1;i<N;i++)
printf ("%lf %lf\n", i*h, central[i]);
return 0;
}
114 5. NUMERICAL DIFFERENTIATION
The output is
$ gcc prog.c
$ ./a.out
x Central
---------------------------
0.100000 0.993000
0.200000 0.978500
0.300000 0.954000
0.400000 0.919500
0.500000 0.876000
0.600000 0.824000
0.700000 0.763500
0.800000 0.695500
0.900000 0.620500
1.000000 0.541500
5.3 EXERCISES
1. Derive the formula similar to Eq. (5.10) but at x D 0 (first point).
2. The altitude (ft) from the sea level and the corresponding time (sec) for a fictitious rocket
were measured as shown in Table 5.3.
Table 5.3: Time and altitude
Time 0 20 40 60 80 100
Altitude 370 9,170 23,835 45,624 62,065 87,368
Numerically compute the velocity from the table above for t D 0–200 keeping the same
accuracy as the central difference scheme. At t D 200, use Eq. (5.10) and at t D 0, use the
formula derived in Problem 1.
115
CHAPTER 6
Numerical Integration
6.1 INTRODUCTION
Any function if given explicitly can be differentiated analytically but very few functions can be
integrated analytically1 which is why numerical integration is more important than numerical
differentiation. While analytical integration is a difficult task in general, it is graphically equiv-
alent to computing the area surrounded by f .x/, the x axis and the lower and upper bounds of
the integration.
There are three methods widely used to numerically integrate a function, f .x/. They are
(1) the rectangular rule, (2) the trapezoidal rule, and (3) Simpson’s rule. As will be shown in
the subsequent sections, Simpson’s rule gives the best approximation and is used as the de-facto
numerical integration standard.
y = f (x)
f0 f1 f2
fn-1 fn
x
0 a h b
Figure 6.1: Rectangular rule.
116 6. NUMERICAL INTEGRATION
rule, the integration, I , can be approximated by
I h f0 C h f1 C h f2 C C h fn 1
D h .f0 C f1 C C fn 1 / ; (6.1)
where h D .b a/=n is the step size and f0 ; f1 ; f2 ; : : : fn 1 are the selected values of the rect-
angles equally divided over Œa; b starting from a (the lower bound). As an example, consider
Z 1
1
I D 2
dx:
0 1Cx
As this integration can be carried out analytically2 and the exact value is =4, it can be used
as a benchmark for the accuracy of each numerical integration scheme. The rectangular rule of
Eq. (6.1) can be implemented as
#include <stdio.h>
double f(double x)
{return 4.0/(1.0+x*x) ; }
int main()
{
int i, n;
double a=0.0, b=1.0, h, s=0.0 , x ;
printf("Number of partitions = ");
scanf("%d", &n) ;
h = (b-a)/n ;
for (i= 0;i<n;i++) s = s + f(a + i*h) ;
s=s*h ;
printf("Result =%lf\n", s) ;
return 0;
}
The output is
$ gcc rectangle.c
$ ./a.out
Number of partitions = 10
Result =3.239926
$ ./a.out
Number of partitions = 100
Z b
2 f .x/dx D arctan xj10 D :
a 4
6.3. TRAPEZOIDAL RULE 117
Result =3.151576
$ ./a.out
Number of partitions = 10000
Result =3.141693
$ ./a.out
Number of partitions = 100000
Result =3.141603
$ ./a.out
Number of partitions = 1000000
Result =3.141594
It is seen that the convergence is marginal. To obtain accuracy of 5 significant figures, 1,000,000
iterations are needed.
f (x)
f0 f1 f2
fn-1 fn
x
0 a b
h h
Figure 6.2: Trapezoidal rule.
#include <stdio.h>
double f(double x)
{return 4.0/(1.0+x*x);}
int main()
{
int i, n ;
double a=0.0, b=1.0 , h, s=0.0, x;
printf("Enter number of partitions = ");
scanf("%d", &n) ;
h = (b-a)/n ;
for (i=1;i<=n-1;i++) s = s + f(a + i*h);
s=h/2*(f(a)+f(b))+ h* s;
printf("%20.12f\n", s) ;
return 0;
}
The output is
$ gcc trapezoid.c
$ ./a.out
Enter number of partitions = 10
3.139925988907
$ ./a.out
Enter number of partitions = 100
3.141575986923
$ ./a.out
Enter number of partitions = 1000
3.141592486923
It is seen that the convergence is much faster than the rectangular rule.
y = ax2 + bx + c
f (0)
f (h)
f (-h)
0
-h h
The curve that passes . h; f . h//, .0; f .0// and .h; f .h// is assumed to be
y D ax 2 C bx C c:
Imposing the condition that this equation passes the three points yields
f . h/ D ah2 bh C c;
f .0/ D c;
f .h/ D ah2 C bh C c;
from which a, b , and c can be solved as
f .h/ C f . h/ 2f .0/
a D ;
2h2
f .h/ f . h/
b D ;
2h
c D f .0/:
Now that y is determined, its integral from h to h is
Z h Z h
2 f .h/ C f . h/ 2f .0/ 2 f .h/ f . h/
.ax C bx C c/dx D x C x C f .0/ dx
h h 2h2 2h
h
D .f . h/ C 4f .0/ C f .h// : (6.3)
3
120 6. NUMERICAL INTEGRATION
The result in Eq. (6.3) implies that the area defined by a curve that passes . h; f . h//, .0; f .0//,
and .h; f .h// is expressed as a weighted average of f . h/, f .0/ and f .h/ with the weight of 1,
4, 1 as
Z h
f . h/ C 4f .0/ C f .h/
y dx D .2h/:
h 6
By applying this for each segment in the interval Œa; b, one obtains
h
I ..f0 C 4f1 C f2 / C .f2 C 4f3 C f4 / C C .f2n 2 C 4f2n 1 C f2n //
3
h
.f0 C 4f1 C 2f2 C 4f3 C 2f4 C C 2f2n 2 C 4f2n 1 C f2n / ; (6.4)
3
where
b a
hD :
2n
Equation (6.4) is known as Simpson’s rule. Note that the number of partitioning for Simpson’s
rule must be an even number (D 2n). For the coding purpose, it is convenient to rewrite Eq. (6.4)
as
h
I D .f0 C f2n /
3
h
C 4 .f1 C f3 C f5 C C f2n 1/
3
h
C 2 .f2 C f4 C f6 C C f2n 2/ : (6.5)
3
Simpson’s rule in Eq. (6.5) can be implemented by the following code:
#include <stdio.h>
double f(double x)
{return 4.0/(1.0+x*x);}
int main()
{
int i, n ;
double a=0.0, b=1.0 , h, s1=0.0, s2=0.0, s3=0.0, x;
printf("Enter number of partitions (must be even) = ");
scanf("%d", &n) ;
h = (b-a)/(2.0*n) ;
s1 = (f(a)+ f(b));
for (i=1; i<2*n; i=i+2) s2 = s2 + f(a + i*h);
for (i=2; i<2*n; i=i+2) s3 = s3 + f(a + i*h);
printf("%20.12lf\n", (h/3.0)*(s1+ 4.0*s2 + 2.0*s3)) ;
6.5. EXERCISES 121
return 0;
}
The output is
$ gcc simpson.c
$ ./a.out
Enter number of partitions (must be even) = 10
3.141592652970
$ ./a.out
Enter number of partitions (must be even) = 20
3.141592653580
As seen in the output above, the convergence is attained with only 10 partitions. Simpson’s
rule is the de-facto standard of numerical integration. It is tempting to extend Simpson’s rule
to approximate f .x/ by a third order polynomial and beyond. However, such attempts are in
general overkill and do not improve accuracy much.
According to error analysis, the truncation error for each rule is as follows:
• Rectangular rule
I A C f 0 ./h
• Trapezoidal rule
I A C f 00 ./h2
• Simpson’s rule
I A C f 000 ./h3
where I is the exact integral value, A is its approximation, h is the step size and is a value
within the interval. It is noted from the above that the accuracy of numerical integration not
only depends onp h but also depends on the derivatives of f .x/. For example, if one attempts
to use f .x/ D 1 x 2 to approximate =4 as in the example p code above, its convergence is
extremely slow even with Simpson’s rule. The slope of f .x/ D 1 x 2 tends to infinity as x
approaches to 1. Thus, f 0 ./, f 00 ./, and f 000 ./ become singular, which accounts for the slow
convergence of the numerical integration.
6.5 EXERCISES
1. (a) Evaluate analytically
Z 3 p
2 x 2 C 4x 3dx:
1
122 6. NUMERICAL INTEGRATION
(b) Write a C program to numerically integrate the above using both the rectangular rule
and Simpson’s rule.
2. (a) Evaluate analytically
Z 1
x ln xdx:
0
(b) Write a C program to numerically integrate the above using Simpson’s rule. Note that
ln x ! 1 as x ! 0. So the challenge is how to handle this seemingly singular point at
x D 0.
123
CHAPTER 7
Solving Simultaneous
Equations
7.1 INTRODUCTION
In Chapter 4, numerical techniques for a single equation, f .x/ D 0, were discussed. In this
chapter, numerical methods for solving a set of simultaneous equations are explained. Many
problems in engineering and science end up with solving a set of linear simultaneous equations
after they are discretized and linearized. Solving a set of simultaneous equations is one of the
most important subjects in numerical analysis. If you took a linear algebra course, you must have
learned Cramer’s rule which expresses the solution to linear simultaneous equations using the
determinants of matrices. However, Cramer’s rule is limited to 2 and 3 simultaneous equations
and in real-world applications, it is not unusual that the number of equations can be as large as
1,000,000. For such cases, separate methods must be developed.
A set of linear simultaneous equations can be expressed in matrix-vector format as
Ax D c;
or
0 10 1 0 1
a11 a12 : : : a1n x1 c1
B a21 a22 : : : a2n CB x2 C B c2 C
B CB C B C
B :: :: :: :: CB :: CDB :: C;
@ : : : : A@ : A @ : A
an1 an2 : : : ann xn cn
or, equivalently,
8
ˆ a11 x1 C a12 x2 C a13 x3 C : : : C a1n xn D c1 ;
ˆ
ˆ
ˆ
< a21 x1 C a22 x2 C a23 x3 C : : : C a2n xn D c2 ;
a31 x1 C a32 x2 C a33 x3 C : : : C a3n xn D c3 ; (7.1)
ˆ
ˆ
ˆ ::::::
:̂
an1 x1 C an2 x2 C an3 x3 C : : : C ann xn D cn :
The number n represents the number of equations and the size of the matrix, A.
124 7. SOLVING SIMULTANEOUS EQUATIONS
CRAMER’S RULE
For two and three simultaneous equations, Cramer’s rule is appropriate. The determinant for a
2 2 matrix is defined as
ˇ ˇ
ˇ a11 a12 ˇˇ
ˇ a11 a22 a12 a21 :
ˇ a21 a22 : ˇ
ˇ ˇ
ˇ a11 a12 a13 ˇ
ˇ ˇ
ˇ a21 a22 a23 ˇ a11 a22 a33 C a12 a23 a31 C a21 a32 a13 a13 a22 a31 a12 a21 a33 a23 a32 a11 :
ˇ ˇ
ˇ a31 a32 a33 ˇ
The determinant of n n.n > 3/ matrices can be expressed similar to the above. It consists of
nŠ terms each of which is a product of n elements.
Using the determinants, the solutions for the following two simultaneous equations
a11 x1 C a12 x2 D c1 ;
a21 x1 C a22 x2 D c2 ;
are expressed as
ˇ ˇ
ˇ c1 a12 ˇˇ
ˇ
ˇ c2 a22 ˇ c1 a22 c2 a12
x1 D ˇ ˇD ;
ˇ a11 a12 ˇˇ a11 a22 a12 a21
ˇ
ˇ a21 a22 ˇ
ˇ ˇ
ˇ a11 c1 ˇˇ
ˇ
ˇ a21 c2 ˇ c2 a11 c1 a21
x2 D ˇ ˇD :
ˇ a11 a12 ˇ ˇ a11 a22 a12 a21
ˇ
ˇ a21 a22 ˇ
The above formulas for the solutions are called Cramer’s rule and it is possible to extend
Cramer’s rule for a set of more than three simultaneous equations using the determinant for
matrices of larger size. However, the practical usage of Cramer’s rule is limited to two and three
simultaneous equations. This is due to the efficiency of computing the determinant. In general,
the determinant for an n n matrix consists of nŠ terms as shown for 2 2 and 3 3 matrices
above. Each term has n 1 multiplications. Therefore, the number of multiplications required
for Cramer’s rule for n simultaneous equations is nŠ.n 1/.n C 1/ counting the denominator.
For n D 4, this is 360 and for n D 10, this amounts to 359,251,200. Approximate computational
time for n simultaneous equations with a 100 MFLOPS computer (an old PC) using Cramer’s
rule is estimated, as shown in Table 7.1.1
n 10 12 14 16 18 20
Time 0.4 sec 1 min 3.6 h 41 days 38 yr 16,000 yr
1 Dahmen and Reusken, Numerik für Ingenieure und Naturwissenschaftler, Springer, 2006.
126 7. SOLVING SIMULTANEOUS EQUATIONS
7.2 GAUSS-JORDAN ELIMINATION METHOD
The Gauss-Jordan elimination method2 is a practical method to systematically solve a set of
many simultaneous equations numerically. It is less efficient than the LU decomposition method
discussed in Section 7.3 but is widely taught as one of the primary numerical techniques for
simultaneous equations.
It is based on the principle of linearity (also called the principle of superposition) in which
if there are two linear equations, their linear combination is also yet another equation. For ex-
ample, consider the following two equations:
Multiplying 1 by Eq. (7.2) and 2 by Eq. (7.3) and adding the two yield
.1 a11 C 2 a21 /x1 C .1 a12 C 2 a22 /x2 C : : : C .1 a1n C 2 a2n /xn D 1 c1 C 2 c2 : (7.4)
EXAMPLE
The Gauss-Jordan elimination method is illustrated by the following example. The goal is to
convert Eq. (7.5) to Eq. (7.6) by using the diagonal elements as pivots.
9
2x y C z D 2; =
x C 3y C 3z D 3; (7.5)
;
2x C y C 4z D 1:
)
9
1x C 0y C 0z D‹; =
0x C 1y C 0z D‹; (7.6)
;
0x C 0y C 1z D‹:
Table 7.2 can be used for this conversion.
2 Also known as the Gaussian elimination or row reduction method.
7.2. GAUSS-JORDAN ELIMINATION METHOD 127
Table 7.2: Steps in the Gauss-Jordan elimination method
In the Gauss-Jordan elimination method, the elements in the first row of Table 7.2 are divided
by a11 so that a11 is normalized to be 1 (line (4)). Using a11 D 1 as a pivot, a21 and a31 are
eliminated (lines (8)–(9)). Next, the elements in the second row (line (8)) are divided by a22 so
that a new a22 D 1 is used as the next pivot. Using a22 D 1, a12 and a32 are eliminated (lines
(13)–(15)). Repeat this for a33 . Finally, the lines (19)–(21) are read as
It can be shown that the number of multiplications required for the Gauss-Jordan elimi-
nation method is approximately proportional to n3 . For n D 10, this amounts to 1,000. Compare
this number with the one required for Cramer’s rule (359;251;200).
128 7. SOLVING SIMULTANEOUS EQUATIONS
The inverse of the matrix A can be obtained using the Gauss-Jordan elimination method
by listing the matrix A along with the identity matrix I as
.A j I / ;
i.e.,
0 1 0 1 1 1 1
2 1 1 1 0 0 1 2 2 2
0 0
@ 1 3 3 0 1 0 A ! @ 0 5 7 1
1 0 A
2 2 2
2 1 4 0 0 1 0 2 3 1 0 1
0 6 3 1 1 0 1
1 0 5 5 5
0 1 0 0 9 5 6
!@ 0 1 7
5
1
5
2
5
0 A!@ 0 1 0 10 6 7 A:
1 7 4
0 0 5 5 5
1 0 0 1 7 4 5
#include <stdio.h>
#define N 3
int main()
{
double a[N][N+1]={{2, -1, 1, 2},{-1, 3, 3, 3},{2, 1, 4, 1}};
double pivot,d;
int i,j,k;
{
d=a[i][k];
for(j=k; j<N+1; j++) a[i][j]=a[i][j]-d*a[k][j];
}
}
}
The output is
$ gcc gaussjordan.c
$ ./a.out
x[1]=27.000000
x[2]=31.000000
x[3]=-21.000000
A D LU; (7.7)
where L and U are lower and upper triangular matrices whose components are expressed as
0 1 0 1
1 0 0 ::: 0 u11 u12 u13 : : : u1n
B l21 1 0 ::: 0 C B 0 u22 u23 : : : u2n C
B C B C
B l31 l32 1 : : : 0 C B 0 u33 : : : u3n C
LDB C; U D B 0 C:
B : :: :: : : :: C B : :: :: :: :: C
@ :: : : : : A @ :
: : : : : A
ln1 ln2 ln3 : : : 1 0 0 0 : : : unn
3 This topic can be skipped.
130 7. SOLVING SIMULTANEOUS EQUATIONS
Note that the diagonal elements of L are set to be 1. This decomposition is called LU decomposi-
tion (or LU factorization) and provides the most efficient way of solving simultaneous equations.
The decomposition of Eq. (7.7) is unique as it is possible to find L and U directly. For
example, for a 4 4 matrix, Eq. (7.7) can be written as
0 10 1 0 1
1 0 0 0 u11 u12 u13 u14 a11 a12 a13 a14
B l21 1 0 C B
0 CB 0 u22 u23 C B
u24 C B a21 a22 a23 a24 C
B D C: (7.8)
@ l31 l32 1 0 A@ 0 0 u33 u34 A @ a31 a32 a33 a34 A
l41 l42 l43 1 0 0 0 u44 a41 a42 a43 a44
from which all the elements of lij and uij can be solved as
8
ˆ
ˆ u11 D a11 ; u12 D a12 ; u13 D a13 ;
ˆ
< l21 D ua21
11
; u 22 D a 22 l u
21 12 ; u 23 D a23 l21 u13 ;
a31 a32 l31 u12
ˆ l31 D u11 ; l32 D
ˆ u22
; u33 D a33 l31 u13 l32 u23 ;
:̂ a41 a42 l41 u12
l41 D u11 ; l42 D u22
; l43 D a43 l41 uu13
33
l42 u23
;
u14 D a14 ;
u24 D a24 l21 u14 ;
u34 D a34 l31 u14 l32 u24 ;
u44 D a44 l41 u14 l42 u24 l43 u34 :
Note that the immediate results for uij and lij are used to solve for the next result.
Using the LU decomposition, Ax D c is written as
LUx D c: (7.9)
To solve Eq. (7.9) for x, the following two steps are needed:
or written explicitly as
8
ˆ
ˆ y1 D c 1 ;
<
l21 y1 C y2 D c2 ;
ˆ l31 y1 C l32 y2 C y3 D c3 ;
:̂
l41 y1 C l42 y2 C l43 y3 C y4 D c4 :
The solution for y1 y4 is straightforward as
8
ˆ
ˆ y1 D c1 ;
<
y2 D c2 l21 y1 ;
ˆ y3 D c3 l31 y1 l32 y2 ;
:̂
y4 D c4 l41 y1 l42 y2 l43 y3 :
or, equivalently, as
8
ˆ
ˆ u11 x1 C u12 x2 C u13 x3 C u14 x4 D y1 ;
<
u22 x2 C u23 x3 C u24 x4 D y2 ;
ˆ u33 x3 C u34 x4 D y3 ;
:̂
u44 x4 D y4 :
Solving for x1 x4 is straightforward as well and yields
8
ˆ
ˆ x4 D uy44
4
;
ˆ
< x D y3 u34 x4 ;
3 u33
ˆ x2 D y2 u23ux22
ˆ
3 u24 x4
;
:̂ x D y1 u11 x1 u12 x2 u13 x3 :
1 u11
#include <stdio.h>
#define N 3
int main()
{
double a[N][N+1]={{2, -1, 1, 2},{-1, 3, 3, 3},{2, 1, 4, 1}};
int i,j,k,l;
/* Backward substitution */
for(k=N-1;k>=0;--k){
for(l=k+1;l<N;l++){
a[k][N] = a[k][N]-a[k][l]*a[l][N];
}
}
The output is
$ gcc lu.c
$ ./a.out
x[0]=27.000000
x[1]=31.000000
x[2]=-21.000000
NOTES
1. If A is a symmetric matrix (aij D aji ), the LU-decomposition is called the Cholesky de-
composition. The number of operations required for the Cholesky decomposition is further
reduced to approximately n3 =6.
3. If A is a triangular diagonal matrix (typical of matrices used in the finite element method),
so are L and U .
Equations (7.12) can be solved iteratively starting with x0 ; y0 ; z0 chosen by initial guess. This
scheme is called the Jacobi method. A slightly better iteration scheme is to use the most immediate
preceding values for the next approximation, i.e.,
8
< xnC1 D .10 yn 2zn /=7;
ynC1 D .8 xnC1 3zn /=8; (7.13)
:
znC1 D .6 2xnC1 3ynC1 /=9:
This scheme is called the Gauss-Seidel method. The Gauss-Seidel method is faster than the Jacobi
method as it uses the most immediate values for the iterations. It is straightforward to implement
the Gauss-Seidel method. As any statement in C uses the most immediate value for variable
substitutions, the Gauss-Seidel method is automatically chosen over the Jacobi method when
coding. In the following code, .x0 ; y0 ; z0 / D .0; 0; 0/ was chosen as the initial guess:
#include <stdio.h>
int main()
{
double x, y, z;
int i,n;
x=y=z=0.0;
printf("Enter # of iteration = ");
scanf("%d", &n);
for (i=0;i<n;i++)
{
x = (10-y-2*z)/7;
y = (8-x-3*z)/8.0;
z = (6-2*x-3*y)/9.0;
}
printf("x = %lf, y= %lf, z=%lf\n", x,y,z);
return 0;
}
7.5. EXERCISES 135
The output is
$ gcc gauss-seidel.c
$ ./a.out
Enter # of iteration = 9
x = 1.281553, y= 0.796117, z=0.116505
$ ./a.out
Enter # of iteration = 10
x = 1.281553, y= 0.796117, z=0.116505
7.5 EXERCISES
1. Solve the following five simultaneous equations by the Gauss-Jordan elimination method:
8
ˆ a11 x1 C a12 x2 C a13 x3 C a14 x4 C a15 x5 D c1 ;
ˆ
ˆ
ˆ
< a21 x1 C a22 x2 C a23 x3 C a24 x4 C a25 x5 D c2 ;
a31 x1 C a32 x2 C a33 x3 C a34 x4 C a35 x5 D c3 ;
ˆ
ˆ
ˆ a31 x1 C a32 x2 C a33 x3 C a44 x4 C a45 x5 D c4 ;
:̂
an1 x1 C an2 x2 C an3 x3 C a54 x4 C a55 x5 D c5 ;
where aij is given as
a[5][5]={
{3.55618, 5.87317, 7.84934, 5.6951, 3.84642},
{-4.82893, 8.38177, -0.301221, 5.10182, -4.1169},
{-7.64196, 5.66605,3.20481, 1.55619, -1.19814},
{-2.95914, -9.16958,7.3216, 2.39876, -8.1302},
{-8.42043, -0.369407, -5.4102, -8.00545, 9.22153}
};
5 To be more exact, if the largest eigenvalue, , of A is greater than 1, the scheme converges.
136 7. SOLVING SIMULTANEOUS EQUATIONS
and ci is given as
CHAPTER 8
Differential Equations
Differential equations are the most important type of equations in scientific computation as ev-
ery physical phenomenon in nature is described by differential equations. We can sense physical
objects because we can capture the rate of the change of the objects and the equations to de-
scribe this rate of change are the differential equations. Solving the Navier-Stokes equations
in fluid mechanics can predict weather patterns as weather is determined by the movement of
air particles. Similarly, solving the stress equilibrium equations in solid mechanics can predict
the strength and durability of materials used and solving the energy equation in heat transfer
can predict the temperature distribution around us all of which are described by differential
equations.
However, solving differential equations analytically is a daunting task to say the least.
Differential equations have been studied over the past 400 years but many useful and impor-
tant differential equations have no analytical solutions available. The good news is that solving
differential equations (initial value problems) numerically does not require an advanced level of
mathematics as will be illustrated in this chapter.
There are two types of differential equations—initial value problems and boundary value
problems. This chapter restricts the scope to initial value problems only and Euler’s method and
the Runge-Kutta method are introduced as the numerical schemes.
dy
D f .t; y/; (8.1)
dt
where y is an unknown function, t is the independent variable, and f .t; y/ is a function of t and
y . Equation (8.1) along with the initial condition of
y.t0 / D y0
y (t)
y1
Starting
y0
t
0 t0 t1
dy ynC1 yn
:
dt h
Therefore, Eq. (8.1) is approximated as
ynC1 yn
D f .t; y/: (8.2)
h
Equation (8.2) can be written as
which can be used to predict ynC1 from yn and the slope at that point as shown in Figure 8.2.
Example 1
Consider the following initial value problem:
dy
D y; y.0/ D 1: (8.4)
dt
8.1. INITIAL VALUE PROBLEMS 139
y
Prediction
y(t)
Exact
y0
Starting
t
0 t0 t1
y D et :
#include <stdio.h>
#include <math.h>
double f(double t, double y)
{
return y;
}
int main()
{
double h=0.1, y, t;
int i;
t=0.0; y = 1.0;
printf("t Euler Exact\n");
for (i=0; i<= 10; i++)
{
140 8. DIFFERENTIAL EQUATIONS
The output is
As seen from the table above, the accuracy of Euler’s method is marginal at best. Despite its
mediocre performance, Euler’s method is robust and can be used to obtain a quick result.
1 Edward Lorenz (1917–2008) was a mathematician, meteorologist and a pioneer of chaos theory.
8.1. INITIAL VALUE PROBLEMS 141
values are chosen.
du
D p.v u/;
dt
dv
D uw C Ru v;
dt
dw
D uv bw: (8.5)
dt
The following code solves Eqs. (8.5) using Euler’s method. The three parameters are chosen as
P D 16:0, b D 4:0, and R D 35:0 and the initial values are chosen as u D 5:0; v D 5:0; w D 5:0.
The step size is chosen as h D 0:01 and 3,000 iterations are performed.
#include <stdio.h>
#define P 16.0
#define b 4.0
#define R 35.0
int main()
{
double h, t, u, v, w;
int i;
/* initial values */
t=0.0; h=0.01;
u=5.0; v=5.0; w=5.0;
In order to plot .u; w/ from the program, gnuplot, a freely available graphic package introduced
in Appendix A, can be used. The output from a.out is saved to a data file, lorenz.dat, using
I/O redirection and this file is placed or transferred to a directory gnuplot can access to.
$ gcc lorenz.c
$ ./a.out > lorenz.dat
Transfer lorenz.dat to a directory accessible by gnuplot. Launch gnuplot and issue the fol-
lowing command:
The pattern in Figure 8.3 was named chaos2 by Lorenz as Eqs. (8.5) are deterministic yet
the result of the trajectory, .u; w/, in Figure 8.3 is neither periodic, convergent, nor divergent. By
2 Also called a strange attractor.
8.1. INITIAL VALUE PROBLEMS 143
imposing a small perturbation on the parameters and initial values, the pattern from Eqs. (8.5)
changes drastically. Refer to Problem 2 in Exercise 8.3 for another example. As the pattern in
Figure 8.3 resembles a butterfly, such observation was later named as the butterfly effect.3
#include <stdio.h>
#include <math.h>
double f(double t, double y)
{return y;}
int main()
{
double h=0.1, t, y, k1,k2,k3,k4;
int i;
/* initial value */
t=0.0; y=1.0;
for (i=0; i<=10; i++)
{
printf("t= %lf rk= %lf exact=%lf\n", t, y, exp(t));
k1=h*f(t,y);
3A movie, The Butterfly Effect (2004), was created after this naming.
4 Pronounced as roo ng-uh-koo t-ah. Both are German mathematicians.
5 For instance, Iserles, A First Course in the Numerical Analysis of Differential Equations (2nd ed.), Cambridge University Press,
2008.
144 8. DIFFERENTIAL EQUATIONS
k2=h*f(t+h/2, y+k1/2.0);
k3=h*f(t+h/2, y+k2/2.0);
k4=h*f(t+h, y+k3);
y= y+(k1+2.0*k2+2.0*k3+k4)/6.0;
t=t+h;
}
return 0;
}
The output is
As seen in the output above, the Runge-Kutta method yields much accurate approximation
compared with Euler’s method. It is the de-fact standard for solving initial value problems.
#include <stdio.h>
#include <math.h>
double f1(double x, double y1, double y2)
{return y2;}
double f2(double x, double y1, double y2)
{return -y1;}
int main()
{
double h=0.01, y1, y2, x;
int i;
y1=0.0; y2=1.0;
x=0.0;
printf(" x y2 cos(x)\n");
for (i=0; i<=10; i++)
{
printf("x= %lf %lf %lf\n", x, y2, cos(x));
y1=y1+h*f1(x,y1,y2);
y2=y2+h*f2(x,y1,y2);
x=x+h;
146 8. DIFFERENTIAL EQUATIONS
}
return 0;
}
Similarly, a third-order differential equation and beyond can be also converted into a set of
simultaneous first-order differential equations.
8.3 EXERCISES
1. Solve the following differential equation:
y0 D x 2 y; y.0/ D 1;
by
(a) exactly (analytically),
(b) Euler’s method, and
(c) the Runge-Kutta method,
and plot the three results in a single graph using gnuplot (Appendix A). Use 0 x 1
and h D 0:1. Use the following syntax in gnuplot:
k D 0:4; B D 20:0;
and show the graph as well. You can use the following as the initial condition:
u.0/ D 1; v.0/ D 1:
Also, use
h D 0:01; i D 10;000:
One shows chaos and the other does not.
149
APPENDIX A
Gnuplot
The C language itself does not support graphics in the standard library as drawing graphics is
machine-dependent. To visualize what a C program outputs in C, it is necessary to use machine-
specific library files which are not part of the gcc distribution. An alternative is to export data
created by a C program to an external application that can read the data file and plot the data.
The graphical application, gnuplot,1 meets such a requirement. For Windows PCs,
download the zipped distribution file from http://www.gnuplot.info. Once downloaded,
extract all the files into the same directory and run wgnuplot.exe from there.
The following is a list of the commands in gnuplot that are often used. Comments in
gnuplot begins with the “#” symbol. Most of them are self-explanatory. Try typing all by your-
self.
To draw the graph shown in Figure A.1, enter the following commands:
1 Freely available for Windows, iOS, and Linux. Source code is also available.
150 A. GNUPLOT
#include <stdio.h>
#include <math.h>
int main()
{
int i; float x;
for (i=0; i<100; i++)
{
x = 0.1*i;
printf("%f %f\n", x , sin(x));
}
return 0;
}
151
The output is
The output from a.out is saved to a file, data.dat. Move this file to a directory where gnuplot
can access. For this purpose, we choose the directory, C:\tmp in the Windows system as a work-
ing directory.
Now open gnuplot and issue the following:
Note that the file name, data.dat, must be enclosed by the single quotation marks (').2 Fig-
ure A.2 shows the output.
For another example of plotting data generated by C, refer to Example 2 in Section 8.1.1.
2 The double quotation mark (") works as well.
152 A. GNUPLOT
To export a graph from gnuplot to another application such as Word, right click the top
bar of the graph window, choose Options, and choose Copy to Clipboard. The graphic image
is save to memory that can be pasted to any application.
Alternatively, it is possible to save a graph from gnuplot directly to a separate file in the
supported graphic formats. The graphic format supported by gnuplot includes jpg, gif, png,
and eps. To save a graph in gif format, issue the following:
There are more commands available in gnuplot that cannot be covered in this Appendix.
gnuplot also has a capability of being used as a scripting language. Refer to many online tutorials
or reference books.3
3 For example, Janert, Gnuplot in Action: Understanding Data with Graphs, Manning Publications, 2009.
153
APPENDIX B
1. There is no distinction between integers and floating points. All variables are double pre-
cision by default.
4. Due to its original philosophy,2 any set of numbers is entered as a matrix including a single
variable. An interval is also entered by a matrix.
5. To define vectors and matrices, the square brackets are used, i.e., [3 4 1], [1 2 3; 4 5
6; 7 8 9].
8. Both a double quotation mark (") and a single quotation mark (') can be used for a string
in Octave but MATLAB only accepts a single quotation mark (').
Try entering the following commands from a command line. Most of the commands are
self-explanatory.
2 MATLAB is an abbreviation for Matrix Laboratory, originally developed for solving problems in linear algebra.
B.2. BASIC OPERATIONS 155
The reserved constants in Octave/MATLAB can be assigned user supplied values. In the exam-
ple below, pi is assigned a user supplied value of 3.0 and this value is kept until the next clear
pi command is issued. As a result of this rule, variables
p such as i and j can be used as iteration
variables even though they were pre-defined as 1.
octave.exe:1> pi
ans = 3.1416
octave.exe:2> pi=3.0 % User defined value.
pi = 3
156 B. OCTAVE (MATLAB) TUTORIAL FOR C PROGRAMMERS
B.2.3 VECTORS/MATRICES
Both vectors and matrices use the square bracket [ ] to store their components. To separate
each component, use a space or a comma (,). For example,
a=[1 4 5; 8 1 2; 6 9 -8];
b=[4; 7; 0];
sol = inv(a)*b % sol = a\b also works.
Although Octave/MATLAB can perform mathematical operations other than linear al-
gebra (matrices/vectors), its underlying design principle is to process numbers as matrices (in-
cluding vectors). This includes defining an interval range as a row vector and the corresponding
function values:
1 3 5 7 9
1 3 5 7 9
1 9 25 49 81
1 1 1 1 1
B.2.4 GRAPH
Both MATLAB and Octave have built-in graphics support. In Octave, built-in gnuplot is
automatically called for graphics. Try the following graphics commands:
close;
%%%%%%%%%%%%%%%%%
t=[0: 0.02: 2*pi];
plot(cos(3*t), sin(2*t)) % Parametric plot.
%%%%%%%%%%%%%%%%%%%%
x=[0: 0.01: 2*pi];
y1=sin(x);
B.2. BASIC OPERATIONS 159
y2=sin(2*x);
y3=sin(3*x);
plot(x, y1, x, y2,x, y3); % Plotting multiple graphs.
%%%%%%%%%%%%%%
xx=[-10:0.4:10];
yy=xx;
[x,y]=meshgrid(xx,yy);
z=(x .^2+y.^2).*sin(y)./y;
surfc(x,y,z) % 3-D graph.
close
B.2.5 I/O
Octave/MATLAB has several options for input/output. There is no scanf() function in Oc-
tave/MATLAB. The input function can be used as shown in the example below as a combina-
tion of scanf() and printf() in C. The printf() function in C is replaced by the fprintf()
function:
B.2.6 M-FILES
There are two types of external files that can be loaded into Octave/MATLAB. They are called
script m-files and function m-files. Both types must have the extension m (*.m) and reside in the
path Octave/MATLAB can search.
1. Function m-files
In C, functions must be declared before they are used. In Octave/MATLAB, a separate
file has to be prepared to use a user-defined function. A file that has the definition of the
user-defined function must be saved under the same name as the function name with m
as the file extension. If that file exists in a directory Octave/MATLAB can access, that
function is automatically loaded into Octave/MATLAB and can be used as if it were a
built-in function. It is not necessary to explicitly load that m-file (in fact, it will cause an
error). For instance, if a file, myfunction.m, exists whose content is
function y=myfunction(x)
y=x^3-x+1;
[a,b]=myfunction2(3);
B.2. BASIC OPERATIONS 161
There is a way to define a function without a separate file using anonymous functions. Use
the following example:
2. Script m-files
A script m-file is a batch file that contains a set of statements that are otherwise typed
from the keyboard. Any Octave/MATLAB statement can be included in a script m-file
except for function definitions that must be separately saved as function m-files. To load a
script m-file, type the file name without extension, m.3 For instance, consider a file whose
name is myscript.m prepared with the following content saved in the C:\tmp directory:
a=input('Enter a number=');
fprintf('The square of %f is %f\n.', a, a^2);
if a>2
disp('a is larger than 2.')
else
3A script m-file name should not contain a minus (-) sign. Why?
162 B. OCTAVE (MATLAB) TUTORIAL FOR C PROGRAMMERS
2. For statement
The following example shows the usage of for statements. Note that for must be paired
with end:
fp2=fopen("data2.dat","w");
fprintf(fp2,"This is the "
"first file.\n");
fclose(fp2);
return 0;
}
B.4 EXERCISES
1. Translate the following C code to an equivalent Octave/MATLAB m-file:
#include <stdio.h>
int main()
{
double x, y, z;
int i,n;
x=y=z=0.0;
printf("Enter # of iteration = ");
scanf("%d", &n);
for (i=0; i<n; i++)
{
x = (10-y-2*z)/7;
y = (8-x-3*z)/8.0;
z = (6-2*x-3*y)/9.0;
}
printf("x = %lf, y= %lf, z=%lf.\n", x,y,z);
168 B. OCTAVE (MATLAB) TUTORIAL FOR C PROGRAMMERS
return 0;
}
/* Simpson's rule */
#include <stdio.h>
#include <math.h>
double f(double x)
{return 4.0/(1.0+x*x);}
int main()
{
int i, n ;
double a=0.0, b=1.0 , h, s1=0.0, s2=0.0, s3=0.0, x;
printf("Enter number of partitions (must be even) = ");
scanf("%d", &n) ;
h = (b-a)/(2.0*n) ;
s1 = (f(a)+ f(b));
for (i=1; i<2*n; i=i+2) s2 = s2 + f(a + i*h);
for (i=2; i<2*n; i=i+2) s3 = s3 + f(a + i*h);
printf("%lf\n", (h/3.0)*(s1+ 4.0*s2 + 2.0*s3));
return 0;
}
169
APPENDIX C
1. Case insensitive. Originally only uppercase letters were used but today a program can mix
both uppercase and lowercase letters.
(a) Column 1 is reserved for comments. If any character is written in Column 1, that
line is interpreted as a comment line.
(b) Columns 2–5 are reserved for line identification (mainly used by GOTO statements).
170 C. FORTRAN TUTORIAL FOR C PROGRAMMERS
(c) Column 6 is reserved for continuation. If any character is written on Column 6, that
line is interpreted as a continuation line from the previous line.
(d) Columns 7–72 are reserved for a FORTRAN statement. This is the only space a
FORTRAN code can be written to.
3. Variables beginning with I-N are automatically declared as integers by default. All other
variables are implicitly declared as real numbers. To override this rule, it is necessary to
explicitly declare variables as INTEGER, REAL, or DOUBLE PRECISION.
1. UNIX system
On a typical UNIX system, either g77 (GNU FORTRAN compiler) or f77 (hard-
ware/software manufacturer supplied FORTRAN compiler) is available. Instead of run-
ning gcc, run g77 followed by the name of FORTRAN file. The file extension of FOR-
TRAN file must be .f or .f77.
$ nano MyProgram.f
$ g77 MyProgram.f
$ ./a.out
C.3. SKETCH OF COMPARISON BETWEEN C AND FORTRAN 171
2. Windows system
Free FORTRAN, g77, for the Windows system is available from the same site that gcc
was downloaded. As the site to download changes over the time, do Google search for
keywords such as gnu g77 windows for the current download site.
To compile a FORTRAN program, issue
g77 MyProgram.c
Note:
• The WRITE(*,*) "STRING", A line means to write STRING and the value of A to the
default device (the first *, screen) using the default format (the second *).
• A to the power of B (AB ) can be entered as A**B.
• The following is a list of relational operators used in IF:
– A.LE.B A is less than or equal to B (a<= b).
– A.LT.B A is less than B (a < b).
– A.EQ.B A is equal to B (a == b).
– A.GT.B A is greater than B (a > b).
– A.GE.B A is greater than or equal to B (a >= b).
– A.NE.B A is not equal to B (a != b).
C.3. SKETCH OF COMPARISON BETWEEN C AND FORTRAN 173
– A.AND.B A and B (a && b).
– A.OR.B A or B (a jj b).
2. Programs for series summation:
STOP
END
• The type of of each function defined must be also declared within the main program.
C.3. SKETCH OF COMPARISON BETWEEN C AND FORTRAN 177
5. Programs to handle external files:
• To access an external file, use OPEN to open the file, assign a unit number to
UNIT and specify whether the file is for writing (STATUS='new') or for reading
(STATUS='old').
• READ(1, *) A means to read a variable, A, from a unit 1 (in this case, an external
file, data1.dat) using default format.
• WRITE(2, *) B means to write the value of B to a unit 2 (in this case, an external
file, data2.dat) using default format.
178 C. FORTRAN TUTORIAL FOR C PROGRAMMERS
C.4 EXERCISES
1. Translate the following C code to a FORTRAN code:
#include <stdio.h>
#define N 10
int main()
{
float x[N]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
y[N]={549.88, 693.932, 415.337, 624.482,
436.095, 355.256, 185.603,
308.003, 244.414, 376.182};
float xysum=0.0, xsum=0.0, ysum=0.0, x2sum=0.0;
float a, b;
int i;
#include <stdio.h>
#include <math.h>
double f(double t, double y)
{return y;}
int main()
{
double h=0.1, t, y, k1,k2,k3,k4;
C.4. EXERCISES 179
int i;
/* initial value */
t=0.0; y=1.0;
Author’s Biography
SEIICHI NOMURA
Seiichi Nomura is a Professor in the Department of Mechanical and Aerospace Engineering at
the University of Texas at Arlington. He is the author of Micromechanics with Mathematica and
coauthor of Heat Conduction in Composite Materials with A. Haji-Sheikh. His research interests
include micromechanics, analysis of composite materials, and applications of computer algebra
systems. He holds a Dr. of Eng. degree from the University of Tokyo and a Ph.D. from the
University of Delaware.
183
Index