Lecture Notes - Mathematics and Statistics

COMO 102 : Scientific Programming, Lecture Notes 2003
Computational Modelling 102
(Scientific Programming)
Lecture Notes
Dr J. D. Enlow
Last modified August 25, 2003.
1
Contents
1 Preliminary Material
5
1 Introduction
1.1 Course Information . . . . . . . . . . . . . . . . . .
1.1.1 Aims of the Course . . . . . . . . . . . . . .
1.1.2 Teaching Methods . . . . . . . . . . . . . .
1.2 Introduction to Scientific Programming . . . . . . .
1.2.1 Introduction to Numerical Methods . . . . .
1.2.2 Numerical Solutions versus Exact Solutions
1.3 Introduction to MATLAB . . . . . . . . . . . . . .
1.3.1 Brief History of MATLAB . . . . . . . . . .
.
.
.
.
.
.
.
.
6
6
6
6
6
9
9
10
10
.
.
.
.
.
.
.
.
.
.
.
.
11
11
12
12
13
13
14
15
15
15
16
16
16
.
.
.
.
.
18
18
19
20
20
23
4 MATLAB’s M-files
4.1 Script m-files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Function m-files . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1 plotData - A More Complicated Example . . . . . . . . . . .
25
25
26
27
2 Revision: Linear Algebra
2.1 Vectors . . . . . . . . . . . . . . . . . . . .
2.1.1 Examples of Basic Operations . . .
2.1.2 Examples using MATLAB notation
2.1.3 Linear Combinations . . . . . . . .
2.1.4 Representing Vectors as Arrows . .
2.1.5 The Dot Product . . . . . . . . . .
2.1.6 Unit Vectors . . . . . . . . . . . . .
2.1.7 Orthogonal Vectors . . . . . . . . .
2.1.8 Orthonormal Vectors . . . . . . . .
2.2 Matrices . . . . . . . . . . . . . . . . . . .
2.2.1 Matrices and Vectors in MATLAB
2.2.2 Matrix Operations . . . . . . . . .
3 Graphics in MATLAB
3.1 Vectorisation and Array Operators .
3.1.1 Array Operators in MATLAB
3.2 Plotting in Two Dimensions . . . . .
3.2.1 The Plot Command . . . . .
3.2.2 MATLAB’s Help Files . . . .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
COMO 102 : Scientific Programming, Lecture Notes 2003
4.2.2 Use of Subfunctions . . . . . . . . .
4.3 Flow Control: If statements and for loops .
4.3.1 Relational Operators . . . . . . . .
4.3.2 The if statement in MATLAB . .
4.3.3 Using for loops in MATLAB . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
27
29
30
32
32
5 Differential Equations: Euler’s Method
5.1 Derivatives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 Introduction: ODEs . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.1 Example: Newton’s Law of Motion as an ODE . . . . . . .
5.2.2 Example: Newton’s Law of Cooling . . . . . . . . . . . . .
5.3 Strategy for the Numerical Methods . . . . . . . . . . . . . . . . .
5.4 Euler’s Method . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.4.1 Euler’s Method is a series of Straight Line Approximations
.
.
.
.
.
.
.
33
33
33
34
35
36
37
37
6 Programming in MATLAB: The Asteroid Problem
6.1 An Asteroid under Earth’s Gravity . . . . . . . . . .
6.2 One Step of the Asteroids Motion . . . . . . . . . . .
6.2.1 Calculating the Acceleration Vector . . . . . .
6.2.2 Calculating the New Position and Velocity . .
6.2.3 An Algorithm to Solve the Asteroid Problem .
6.2.4 Errors . . . . . . . . . . . . . . . . . . . . . .
6.3 Multiple Planets . . . . . . . . . . . . . . . . . . . .
6.3.1 Three Planets . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
38
38
39
40
40
41
42
43
44
7 Various Topics
7.1 Revision . . . . . . . . . . . . . . . . . . . . . .
7.1.1 Strategy for the Numerical Methods . .
7.1.2 Euler’s Method . . . . . . . . . . . . . .
7.2 ode23 and ode45 . . . . . . . . . . . . . . . . .
7.2.1 ode23 . . . . . . . . . . . . . . . . . . .
7.2.2 ode45 . . . . . . . . . . . . . . . . . . .
7.3 File Input and Output (“I/O”) in MATLAB . .
7.3.1 ASCII and MAT files . . . . . . . . . . .
7.4 Machine Precision . . . . . . . . . . . . . . . . .
7.4.1 Consequences . . . . . . . . . . . . . . .
7.4.2 Example: Modulus of a complex number
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
45
45
45
46
47
47
47
48
48
49
49
51
.
.
.
.
.
.
.
.
52
52
52
52
53
53
53
54
54
8 Programming in C
8.1 Basic Concepts . . . . . . . . . .
8.1.1 Statements . . . . . . . .
8.1.2 Data and variables . . . .
8.1.3 Declarations . . . . . . . .
8.1.4 Pointers . . . . . . . . . .
8.1.5 Arrays . . . . . . . . . . .
8.1.6 Functions . . . . . . . . .
8.1.7 Local and global variables
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
COMO 102 : Scientific Programming, Lecture Notes 2003
8.1.8 Parameters . . . . . . . . . . . . . . . . .
8.2 A Short History of the Language C . . . . . . . .
8.3 A Few Characteristics of the Language C . . . . .
8.3.1 Compiler-based . . . . . . . . . . . . . . .
8.3.2 Extensive Use of Libraries . . . . . . . . .
8.3.3 Shorthand for symbols that are used often
8.4 Libraries . . . . . . . . . . . . . . . . . . . . . . .
8.5 A Sample C Program . . . . . . . . . . . . . . . .
8.5.1 Source Code . . . . . . . . . . . . . . . . .
8.5.2 Compilation and Output . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
55
55
56
56
56
57
57
58
58
58
9 Programming in C Part II
9.1 Variables in C . . . . . . . . . . . . . . . . . . . . .
9.1.1 Variable Declaration . . . . . . . . . . . . .
9.1.2 Printf . . . . . . . . . . . . . . . . . . . . .
9.1.3 Formatting Arguments of Printf . . . . . . .
9.2 Parameters in Subroutines . . . . . . . . . . . . . .
9.3 Pointers . . . . . . . . . . . . . . . . . . . . . . . .
9.3.1 Allowing Permanent Changes in Parameters
9.3.2 Pointer Values . . . . . . . . . . . . . . . . .
9.3.3 Pointers are Useful but *DANGEROUS*! .
9.3.4 Making Pointers Safer . . . . . . . . . . . .
9.3.5 Some Friendly Advice . . . . . . . . . . . .
9.4 Bug Finding and Indenting . . . . . . . . . . . . . .
9.4.1 lclint . . . . . . . . . . . . . . . . . . . . . .
9.4.2 indent . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
59
59
59
60
60
61
62
62
63
63
64
65
65
65
65
10 Programming in C Part III
10.1 Arrays . . . . . . . . . . . . . . . . . . . . .
10.1.1 Passing Arrays to Subroutines . . . .
10.2 Writing output to a file: fprintf . . . . . . .
10.2.1 Exporting Data from C to MATLAB
10.3 Recursion . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
67
67
68
70
71
73
.
.
.
.
.
.
.
.
74
74
74
75
76
77
77
78
79
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
11 Programming in C Part IV
11.1 The Comotank Client-Server Framework . . . . .
11.1.1 The Rules . . . . . . . . . . . . . . . . . .
11.1.2 An Empty Client . . . . . . . . . . . . . .
11.1.3 The Controlling Functions in More Detail
11.1.4 A Simple Tank . . . . . . . . . . . . . . .
11.1.5 Compiling and Testing . . . . . . . . . . .
11.1.6 Utilities Available . . . . . . . . . . . . . .
11.1.7 Tankview . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Chapter 1
Preliminary Material
Lecturer
Dr John Enlow, Room 518, Science III ([email protected] ).
Course structure:
Each week consists of:
• One lecture (in Lab B, Monday at 11am),
• One one-hour tutorial (in Lab A, Wednesdays at 11am).
• One three-hour laboratory (in Lab A, Thursdays from 9am to 12pm).
The laboratory exercise is due at 1pm on Friday.
Assessment:
The internal assessment is comprised of the mid-semester test (40%) and the weekly
exercises (60%). Your final grade is either your final exam score, or one third of your
internal assessment plus two thirds of your final exam score, whichever is greater.
2
1
Final Grade = M AX EXAM, EXAM + I.A.
3
3
Computer Packages Used
The first half of this course will use a commercial scientific package called MATLAB.
The second half will focus on C programming, and you will have access to the Linux
server COMO to write and run your programs on. These tools are available from
Lab A in the mathematics department. If you wish to work from home you can purchase a student version of MATLAB from Hoare research (www.hrs.co.nz), or from
the University Bookshop, and download a free Windows C compiler and integrated
development environment from http://www.bloodshed.net/devcpp.html.
Books
There is no prescribed text for this course.
5
Lecture 1 : Introduction
Chapter 1
1.1
Course Information
Introduction
1.1.1
Aims of the Course
1. To provide a detailed introduction to programming in MATLAB.
2. To briefly introduce programming in C from within a Unix environment.
3. To reinforce ideas from other mathematics papers.
4. To improve your problem solving, modelling and computer skills.
1.1.2
Teaching Methods
The course is primarily hands-on, with four of the five contact hours per week on
computers in Lab A. You will get one small exercise to be done in the tutorial each
week, for which solutions will be provided, and one lab exercise per week which will
count towards your internal assessment. You are expected to spend 12 hours per
week on this course, consisting of the lectures, tutorials and labs as well as several
hours per week working on your own.
1.2
Introduction to Scientific Programming
The scientific programming taught in this course centers on the implementation of
numerical methods to solve real-world problems. Many languages are available to
the scientific programmer for tackling a problem, and the choice of language will often depend on the programmers background and need for collaboration. We use the
word language loosely here, including scripting languages as used in Mathematica
and MATLAB. Key features desired in a language are:
• Accuracy. When solving a problem on computer numerical errors are often of
critical importance. Some languages have poor mathematical routines and/or
low accuracy in their data types. This may depend partly on the compiler.
• Speed. Many high-end ‘nice’ languages, such as Java and Mathematica, provide a long list of advantages over traditional languages, but at the cost of
speed. A complicated numerical method implemented in C or MATLAB can
be orders of magnitude faster than a Java implementation. Other factors can
come into play here - is the language interpreted? Does the compiler contain
optimizations for your type of computer?
6
7
COMO 102: Lecture 1, 2003
• Graphics. Graphical representation of solutions are an important part of the
modelling process. Does the language have convenient methods or libraries for
presenting data? Must you rely on low-level routines? Are standard graphics
libraries available (e.g. OpenGL)? Can you easily export data for use in highlevel software like Mathematica?
• Libraries / Add-on Packages. What mathematical functionality does the language come with? Do you have to implement standard mathematical data
structure types yourself (e.g. vectors, matrices, complex numbers)?
• Portability. Will your program work on other types of computers? As a
scientific programmer you may develop your program on a low-end PC, then
wish to run it on a powerful super-computer.
Of course there are many other considerations, such as whether the code is easy
to read and reusable, whether the language is object orientated, the overhead in
producing code, whether you can produce a nice GUI for your program (if it is to be
used by others), oddities in the language - do you spend time hunting down obscure
bugs that are due to inconsistent language features?
Some languages that you may consider are summarized below:
Language or
Package
Mathematica
MATLAB
JAVA
C++
C
FORTRAN
Design
Symbolic
Numerical
O.O.
O.O.
Numerical
Numerical
Numerical
Speed
Slow
Very fast
Slow
Fast
Very fast
Fastest
GUI
creation
None
Poor
Good
Good
Average
None
Graphics
Capabilities
Good
Good
Average
Average
Average
Poor
Ease of
use
Excellent
Good
Average
Average
Poor
Poor
• Mathematica. Primarily symbolic - relatively slow at numerical work. A very
good tool for developing the theory and which algorithms to use, not very
good for implementation of the algorithm. Nice graphics, good front-end,
easy to use but with a few quirks. Available for Windows, MacOS, and UNIX
environments. Poor facilities for production of a graphical user interface.
• MATLAB. Primarily numerical - very fast at some matrix operations, extensive inbuilt mathematics routines, excellent handling of sparse matrices,
good graphics capabilities. Has ability to write a GUI, but resulting interface is fairly crude, very slow and crash-prone. Not a very elegant system to
work with. Function names are often non-obvious. Available for all major
platforms.
• Java. Heavily object orientated, comes with a large overhead. Portable,
flexible, nice integration with web page interfaces. Not suitable for serious
numerical work.
• C++. Full-featured, fast for numerical work (provided you don’t go classcrazy), flexible. Available for just about every architecture and operating
COMO 102: Lecture 1, 2003
8
system. Many components need to be written ‘from scratch’, however there
are resources on the internet (class libraries) for a wide range of tasks, including plotting and numerically solving problems.
• C. Very fast. Not object orientated, so code is harder to maintain and less
easy to read, but uses less memory and is more compact. Otherwise similar to
C++. MATLAB is written in C, along with an enormous number of programs
from the Linux kernel to Quake III. Note that C is essentially a subset of C++,
so you can use C++ for the user interface and input/output sections of the
code and C for the real work (numerical methods) all in one program.
• Fortran. An older language developed for engineers. Produces code comparable in speed to C (and generally a bit faster). The language has many
frustrating restrictions and can be a nightmare to debug. Still in use by some
programmers, particularly engineers, but people learning to write numerical
algorithms now often use C/C++ instead.
You may find a combination of these languages suits your needs best. E.g.:
• Financial forecasting software with a web interface. Java for the front-end
web components, C for executing the calculations.
• Solving a problem involving a huge amount of data. C for the calculations,
MATLAB for graphing the solutions.
• A user-friendly package to predict heat-flow in a high-temperature industrial
oven. Mathematica for design of the numerical method and model, C++ for
producing the user interface, C for the numerical algorithms.
There are many other languages out there, but few are as suitable for implementing
numerical methods as MATLAB and C. Beware of portability issues, if your code
is to be used for longer than a year or two then portability can become a major
hassle.
This course will primarily use MATLAB, but will also give you a brief introduction to C. It will focus on producing solutions to mathematical models. Your
software will generally not be designed for others to use, as we don’t want to spend
too much time developing nice interfaces. Writing user interfaces can involve a surprising amount of effort! We will look at problems from a variety of areas. If you
have any particular problems from another subject that you’d like to see solved,
please let me know, as the course content is reasonably flexible.
COMO 102: Lecture 1, 2003
1.2.1
9
Introduction to Numerical Methods
Numerical methods are techniques for finding approximate solutions to
mathematical problems. Some numerical techniques have been established for
a long time. For example Euler is credited with having introduced finite differences
in 1768 to approximate derivatives in ordinary differential equations. The finite
difference method, one of many methods available, is capable of producing numerical
solutions to both ordinary and partial differential equations.
Real progress on the development and application of numerical methods is a
product of the 20th century. Early contributions of historical importance were
made by scientists such as Runge, Richardson, Liebmann, Courant, Friedrichs, von
Neumann, among many others.
Due to the widespread availability of computers, which are particularly well
suited to numerical algorithms, numerical methods are now a key technology for
industrial progress in a modern society. The speed and accuracy of modern computers allows the use of simple numerical methods in complicated problems. This
greatly increases the ability of a student with only an introductory mathematical
background to solve real-world problems.
Applications of Numerical Methods
A distinctive feature of numerical analysis is its highly multidisciplinary character;
it involves research workers from a wide spectrum of interests, for example:
• professional numerical analysts,
• computer scientists,
• mathematicians,
• physicists,
• chemists,
• engineers,
• financial modelers.
Numerical methods make it possible to theoretically model and simulate phenomena
of interest from almost any discipline.
1.2.2
Numerical Solutions versus Exact Solutions
Exact solutions:
• provide greater information about the system,
• allow a deeper understanding of the effects of parameters, and
• avoid issues such as numerical error and instability which plague many attempts at numerical solutions.
COMO 102: Lecture 1, 2003
10
However, exact solutions are often obtainable only for simple systems. The approximations required to produce an exact solution may make the solution of little
interest except as a stepping stone towards a numerical solution! Exact solutions
usually require a greater degree of mathematical knowledge and skill than numerical
techniques.
1.3
1.3.1
Introduction to MATLAB
Brief History of MATLAB
• LINPACK and EISPACK developed in mid-1970’s using the (then popular)
computer language FORTRAN. Together, LINPACK and EISPACK represented state of the art software for matrix computation.
• In the late 1970’s Cleve Molar, one of the designers of LINPACK and EISPACK, wanted students to use the subroutines without having to learn FORTRAN. He developed a crude program to be used as a simple interface. He
called it MATLAB, an abbreviation for MATrix LABoratory.
• As Cleve visited universities he left copies of MATLAB on their computers.
Within a year or two, MATLAB started to catch on within the applied math
community.
• In early 1983 an engineer, John Little, recognized the potential application
of MATLAB to engineering applications, and helped Cleve develop a new
version written in C and integrated with graphics.
• The MathWorks, Inc. was founded in 1984 to market and continue development of MATLAB.
Since then MATLAB has grown into a full-featured package for solving both realworld and theoretical problems, primarily using numerical methods operating on
matrices. There are many toolboxes available to extend MATLAB’s functionality,
enabling MATLAB to be used to solve a very wide range of problems. The toolboxes
provide routines involving everything from statistics and optimization to neural
networks and image processing.
Lecture 2 : Revision: Linear Algebra
Chapter
2
MATLAB is entirely based on matrices.
Thus understanding the basics of linear
algebra is crucial. These lectures will provide a review of what should be familiar
material and use MATLAB examples to illustrate the ideas.
Revision: Linear Algebra
2.1
Vectors
A vector is an ordered set of numbers arranged as a row or column. The numbers
in the vector are known as elements or components. Vectors are usually written
enclosed in large round or square brackets, we will use square brackets in this course.
Row vectors can be written with or without commas separating the elements.
A row vector:
~u = [u1 , u2 , u3 , . . . , un ]
A column vector:
~x =






x1
x2
..
.
xm






Recall that the MATLAB function length gives the number of elements in the
vector, not the magnitude of the vector! To minimise confusion we will avoid the
use of the word length, using magnitude when describing the distance from tail to
head of a vector, and dimension when referring to the number of elements in a
vector.
The magnitude of a vector can be expressed as the square root of the sum of
the squares of its elements:
|~u| =
q
u21 + u22 + . . . + u2n .
This distance is |~u|,
i.e. the magnitude of ~u.
~u
Vectors can be used to represent physical quantities that contain directional
information, such as force, acceleration, velocity, displacement. Variable names
representing vectors are drawn with an underscore (x) or overarrow (~x).
11
12
COMO 102: Lecture 2, 2003
So, for example, Newton’s second law of motion can be written as:
F~ = m ~a,
where m, the mass, is a scalar (number) not a vector.
For both row and column vectors we generally label the elements of a vector ~a
with length n as a1 , a2 , . . ., an . This allows compact definitions of vector addition,
subtraction, and scalar multiplication.
Addition is defined only for equal length vectors, and:
~a + ~b = ~c ⇐⇒ ∀i ∈ {1, 2, . . . , n}, ai + bi = ci
Thus, for example, [1, 2, 3] + [4, 5, 6] = [5, 7, 9].
Scalar multiplication is also done element-wise, so that
α ~a = ~b ⇐⇒ ∀i ∈ {1, 2, . . . , n}, α ai = bi
where α is a scalar. Scalar division can be defined in terms of scalar multiplication,
because ~a/α = β ~a, where β = α1 .
Subtraction can be defined as the addition of (the first vector) to (the second
vector multiplied by the scalar -1), i.e. ~b − ~a ≡ ~b + (−1) ~a, thus
~b − ~a = ~c ⇐⇒ ∀i ∈ {1, 2, . . . , n}, bi − ai = ci
2.1.1
Examples of Basic Operations
• [5, 5, 5] − [4, 6, 8] /2 = [3, 2, 1]
• 2 [1, 2, 3] = [2, 4, 6]
• 5 [1, 0, 0] − 2 [0, 1, 0] = [5, −2, 0]
2.1.2
Examples using MATLAB notation
The main difference is that we must use ∗ to indicate multiplication. MATLAB
does not recognise spaces as multiplication!
>> [5, 5, 5] − [4, 6, 8] /2
>> 2 ∗ [1, 2, 3]
>> 5 ∗ [1, 0, 0] − 2 ∗ [0, 1, 0]
ans = [3, 2, 1]
ans = [2, 4, 6]
ans = [5, −2, 0]
13
COMO 102: Lecture 2, 2003
2.1.3
Linear Combinations
A linear combination of objects is the sum of each object multiplied by a scalar.
For example, which of the following are linear combinations of the objects 3, 2, 4
and ♥ ?
• 3+♥
• 3 + ♥ + 4 − 43.82 ∗ 2
• 4∗2
• 42 + 3
• 2∗♥
2 ∗ ♥ − 7.2 ∗ 2
3
In general, a linear combination of two vectors ~u and ~v can be written as:
• 4+
α~u + β~v = α






u1
u2
..
.
um



+β








v1
v2
..
.
vm


α u1 + β v 1



 α u2 + β v 2
=
..




.
α um + β v m



.


where α and β are real scalars.
Linear Combinations of Vectors of Length 3
Consider two position1 vectors of length 3 (i.e. vectors in three dimensional space)
that are not parallel. If we imagine all possible linear combinations of these vectors,
what region in space do we cover?
2.1.4
Representing Vectors as Arrows
A vector has three defining properties:
1. Magnitude
2. Direction
3. Sense
All are clearly represented when it is drawn as an arrow:
The magnitude of the vector is represented by how long the arrow is.
The direction is represented by the orientation of the vector, and is independent
of which end the arrow head is on.
Two vectors with the same direction are said to be parallel, and have either the
same sense or opposite sense. Sense is undefined for non-parallel vectors.
1
A position vector is a vector with it’s tail placed on the origin. It can be used to specify the
position of a point in space.
14
COMO 102: Lecture 2, 2003
Different magitude.
Same direction (parallel).
Opposite sense.
Same magnitude, different direction.
2.1.5
Same magnitude.
Same direction (parallel).
Same sense.
The Dot Product
The dot product is an operation between two vectors of the same dimension (i.e.
with the same number of elements). It produces a scalar not a vector. We define
it as:
n
X
a i bi = a 1 b1 + a 2 b2 + . . . + a n bn
~a · ~b ≡
i=1
In MATLAB we can calculate the dot product of two vectors with the dot function:
>> a=[1 2 3 4]; b=[2 2 2 2];
>> dot(a,b)
ans =
20
The dot product can be used to find the angle between two vectors. In order to
show this we use the cosine rule for a triangle and the distributive law of the dot
product, resulting in2 :
~a · ~b = |~a||~b|cosθ
where θ is the angle between the vectors.
~b
θ
~a
2
me!
The proof of this is excluded in the interests of time. If you’d like to see the proof come ask
15
COMO 102: Lecture 2, 2003
Dot product and Magnitudes
The magnitude of a vector can be calculated using the dot product. To see this
consider ~u · ~u:
~u · ~u = [u1 , u2 , . . . , un ] · [u1 , u2 , . . . , un ]
= u21 + u22 + . . . + u2n
Comparing this with our expression for a vectors magnitude from the first page we
conclude that:
~u · ~u = |~u|2
Properties of the dot product
The dot product is both commutative and distributive:
~a · ~b = ~b · ~a,
and
~a · ~b + ~c = ~a · ~b + ~a · ~c.
Scalars can be moved to the front of the expression from within a dot product, eg
~a · α ~b = α ~a · ~b .
2.1.6
Unit Vectors
A unit vector is a vector with a magnitude of one
(unit magnitude). For example the vector [ 1 0 0 ]
is a unit vector, as is [ √12 0 √12 ].
We can find the unit vector corresponding to any
given vector (except the zero vector) by scaling
the vector by one over its magnitude (proof given
on whiteboard). For example, the vector [ 1 0 1 ]
has associated unit vector:
√
12
2.1.7
1
1
1
∗[ 1 0 1 ]=[ √ 0 √ ]
2
2
+0 +1
2
2
Orthogonal Vectors
Orthogonal vectors are vectors that are perpendicular, i.e. the angle between them
is 90o . We can test for orthogonality using the dot product, as if ~a and ~b are
orthogonal then ~a · ~b = 0.
2.1.8
Orthonormal Vectors
Orthonormal vectors are unit vectors that are orthogonal. For example the vectors
in three dimensions pointing along the coordinate axes, [1 0 0], [0 1 0] and [0 0 1]
are clearly mutually orthonormal, as the dot product of any two is zero, and they
are all unit vectors.
16
COMO 102: Lecture 2, 2003
2.2
Matrices
A matrix is a rectangular array of real or complex numbers. The A matrix with m
rows and n columns is written as
A=






a11
a21
..
.
a12
a22
..
.
. . . a1n
. . . a2n
..
.
am1 am2 . . . amn






Conventionally uppercase roman letters are used to designate an entire matrix.
Elements are written as lowercase letters with two subscripts, the first giving the
row number and the second the column number. A matrix with m rows and n
columns is said to be an m by n matrix.
2.2.1
Matrices and Vectors in MATLAB
In MATLAB the only difference between a vector and a matrix is the number of
rows and columns each contains. Even scalars are treated as 1 by 1 matrices! This
means that the routines which operate on matrices usually work on scalars and
vectors also, although their behaviour may depend on the number of rows and
columns.
2.2.2
Matrix Operations
We give the component-wise rule for the following operations, as well as one example.
Matrix Addition
A + B = C ⇐⇒


∀i, j,

ai,j + bi,j = ci,j



1 2 3
3 3 3
4 5 6

 



 1 2 3 + 4 4 4 = 5 6 7 
1 2 3
5 5 5
6 7 8
Scalar Multiplication
α B = C ⇐⇒

∀i, j,


α bi,j = ci,j

28 35 42
4 5 6



=
5
6
7
7∗
 35 42 49 


42 49 56
6 7 8
17
COMO 102: Lecture 2, 2003
Matrix Subtraction
A − B ≡ A + (−1 ∗ B)






−2 −1 0
3 3 3
1 2 3



 

 1 2 3  −  4 4 4  =  −3 −2 −1 
−4 −3 −2
5 5 5
1 2 3
Matrix Transpose
The matrix transpose is written as AT mathematically, but MATLAB uses the ’
symbol, e.g. A’.
AT = B ⇐⇒ ∀i, j, ai,j = bj,i
T



1 2 3
1 4 7




 4 5 6  = 2 5 8 
7 8 9
3 6 9
Matrix Product
The matrix product is not as simple as the previous operations. In order to calculate
A ∗ B the inner matrix dimensions of A and B must agree. Suppose A is an m by
r matrix, and B is an r by n matrix.
A=






a11
a21
..
.
a12
a22
..
.

. . . a1r
. . . a2r
..
.
am1 am2 . . . amr





B=






If A ∗ B = C then C is an m by n matrix, with elements such that
ci,j =
r
X
k=1
Example:
"
1 2 3
4 5 6
#

ai,k ∗ bk,j


b11 b12 . . . b1n
b21 b22 . . . b2n 

..
..
.. 

.
.
. 
br1 br2 . . . brn
"
#
2 1
32 9


∗ 3 4 =
71 24
8 0
Lecture 3 : Graphics in MATLAB
Chapter
3
Before we learn about graphics and plotting in MATLAB we need to become familiar
with the array operators in MATLAB.
Graphics in MATLAB
3.1
Vectorisation and Array Operators
All of the built-in functions in MATLAB are able to operate on vectors, where
the operation is applied to each element in the vector. For example, if we ask for
the square root of a vector, an operation that is traditionally undefined, MATLAB
complies by taking the square root of each element within the vector. The results
are, of course, outputted as a vector:
>> sqrt([4 9 16])
ans =
2
3
4
Such ‘vectorisation’ allows us to perform operations with compact syntax, as
we don’t have to write a loop that takes the square root of each element one by
one. Of still greater importance is the improved computational efficiency - modern
processors are able to take advantage of vectorisation to compute many operations
simultaneously!
To support vectorisation MATLAB defines new arithmetic symbols called array
operators which perform element-by-element operations on matrices or vectors. Often these operations have no equivalent in formal linear algebra - they are defined
in MATLAB not for their mathematical merit but for convenience and speed of
the resulting code. Array operations view the matrices as data structures, not as
mathematical entities!
In summary, vectorisation:
• Allows compact notation.
• Uses features of modern processors to increase the speed of your code.
• Does not always have mathematical equivalents.
18
19
COMO 102: Lecture 3, 2003
3.1.1
Array Operators in MATLAB
The array operators used for vectorisation in MATLAB are a combination of a full
stop and one of the conventional operators (e.g. .* ./ .^). Remember however
that all the inbuilt scalar functions work element-by-element on vectors also!
Multiplication
Matrix multiplication:






30 24 18
9 8 7
1 2 3


 

69 54 

 4 5 6  ∗  6 5 4  =  84
138 114 90
3 2 1
7 8 9
Vectorised multiplication:






9 16 21
9 8 7
1 2 3






 4 5 6  . ∗  6 5 4  =  24 25 24 
21 16 9
3 2 1
7 8 9
In MATLAB we use the following. Note I have used the reshape function to reshape
easily created row vectors into 3x3 matrices.
>> A=reshape([1:9],3,3)’
A =
1
2
3
4
5
6
7
8
9
>> B=reshape([9:-1:1],3,3)’
B =
9
8
7
6
5
4
3
2
1
>> A.*B
ans =
9
24
21
16
25
16
21
24
9
20
COMO 102: Lecture 3, 2003
Division
Matrix division is undefined. Vectorised division is as you would expect:







9 8 7
1 2 3


 
4 5 6  ./  6 5 4 
=

3 2 1
7 8 9
2
8
5
5
8
2
1
9
4
6
7
3
3
7
6
4
9
1





In MATLAB:
>> A./B
ans =
0.1111
0.6667
2.3333
3.2
0.2500
1.0000
4.0000
0.4286
1.5000
9.0000
Plotting in Two Dimensions
MATLAB generates plots based on arrays or matrices of numerical values. If we
wish to plot a known function we need to create these arrays for MATLAB, as it is
unable to handle symbolic notation1 .
3.2.1
The Plot Command
In it’s most basic form the Plot command takes two vectors of equal length (i.e.
with the same number of components), one vector representing the x values, and
one representing the y values. For example:
>> x = [ 0 1 2 3 4 5];
>> plot(x,y)
y = [ 5 3 6 8 7 4];
8
7.5
7
6.5
6
5.5
5
4.5
4
3.5
3
1
A.
0
0.5
1
1.5
2
2.5
3
3.5
4
4.5
5
MATLAB does have a primitive symbolic manipulation toolbox, but it is not available in LAB
21
COMO 102: Lecture 3, 2003
The graph appears in a new window. By default any further calls to plot will replace
that graph, if we wish to keep it we open a second window by entering the command
figure.
Plot allows us to specify the line style, symbols to draw at the points, and
colours. We can plot multiple sets of data, put on axes labels, place a grid in the
plot, insert plot titles, and so forth. For example, consider the following:
>>
>>
>>
>>
>>
x=linspace(0,2*pi);
y=sin(x);
plot(x,y);
axis([0 2*pi -1.5 1.5])
title(’sin(x)’)
sin(x)
1.5
1
0.5
0
−0.5
−1
−1.5
1
2
3
4
5
6
x=linspace(0,2*pi,20);
y1=sin(x);
y2=sin(x)+rand(size(x))-0.5;
plot(x,y1,’ro-’,x,y2,’b+’);
axis([0 2*pi -1.8 1.8])
xlabel(’angle, x’);
ylabel(’function value’);
legend(’sin(x)’,’randomized sine(x)’);
title(’Plot of sin(x) with and without noise.’);
Plot of sin(x) with and without noise.
sin(x)
randomized sine(x)
1.5
1
0.5
function value
>>
>>
>>
>>
>>
>>
>>
>>
>>
0
0
−0.5
−1
−1.5
0
1
2
3
angle, x
4
5
6
22
COMO 102: Lecture 3, 2003
Note that the line
>> y2=sin(x)+rand(size(x))-0.5;
uses the command rand to create a vector that is the same size as x, with random
numbers between 0 and 1 as its elements. An example of the use of rand is:
>> rand(1,5)
ans =
0.6602
0.3420
0.2897
0.3412
0.5341
We also subtract 0.5 from the resultant vector of random numbers. We can subtract
scalars from vectors, because MATLAB uses array operations to subtract the scalar
from each element of the vector, e.g.:
>> [1 2 3] - 1
ans =
0
1
2
Subtracting 0.5 effectively shifts the random numbers to be centered on the origin, so
rand(size(x))-0.5 represents a vector of the same size as x that contains random
numbers in the range [−0.5, 0.5].
We add this vector of random numbers between −0.5 and 0.5 to sin(x), which
uses the vectorised sin command to calculate the sine of every element in the vector
x. The result is equivalent to:
>> y2 = sin(x) + rand(size(x)) - 0.5*ones(size(x)) ;
Question: why does the following produce significantly different results?
>> y2 = sin(x) +
rand(1) - 0.5 ;
23
COMO 102: Lecture 3, 2003
3.2.2
MATLAB’s Help Files
PLOT
Linear plot.
PLOT(X,Y) plots vector Y versus vector X. If X or Y is a matrix,
then the vector is plotted versus the rows or columns of the matrix,
whichever line up. If X is a scalar and Y is a vector, length(Y)
disconnected points are plotted.
PLOT(Y) plots the columns of Y versus their index.
If Y is complex, PLOT(Y) is equivalent to PLOT(real(Y),imag(Y)).
In all other uses of PLOT, the imaginary part is ignored.
Various line types, plot symbols and colors may be obtained with
PLOT(X,Y,S) where S is a character string made from one element
from any or all the following 3 columns:
y
m
c
r
g
b
w
k
yellow
magenta
cyan
red
green
blue
white
black
.
o
x
+
*
s
d
v
^
<
>
p
h
point
circle
x-mark
plus
star
square
diamond
triangle (down)
triangle (up)
triangle (left)
triangle (right)
pentagram
hexagram
:
-.
--
solid
dotted
dashdot
dashed
For example, PLOT(X,Y,’c+:’) plots a cyan dotted line with a plus
at each data point; PLOT(X,Y,’bd’) plots blue diamond at each data
point but does not draw any line.
PLOT(X1,Y1,S1,X2,Y2,S2,X3,Y3,S3,...) combines the plots defined by
the (X,Y,S) triples, where the X’s and Y’s are vectors or matrices
and the S’s are strings.
For example, PLOT(X,Y,’y-’,X,Y,’go’) plots the data twice, with a
solid yellow line interpolating green circles at the data points.
The PLOT command, if no color is specified, makes automatic use of
the colors specified by the axes ColorOrder property.
COMO 102: Lecture 3, 2003
24
RESHAPE Change size.
RESHAPE(X,M,N) returns the M-by-N matrix whose elements
are taken columnwise from X. An error results if X does
not have M*N elements.
RESHAPE(X,M,N,P,...) returns an N-D array with the same
elements as X but reshaped to have the size M-by-N-by-P-by-...
M*N*P*... must be the same as PROD(SIZE(X)).
RESHAPE(X,[M N P ...]) is the same thing.
In general, RESHAPE(X,SIZ) returns an N-D array with the same
elements as X but reshaped to the size SIZ. PROD(SIZ) must be
the same as PROD(SIZE(X)).
See also SQUEEZE, SHIFTDIM, COLON.
AXIS
Control axis scaling and appearance.
AXIS([XMIN XMAX YMIN YMAX]) sets scaling for the x- and y-axes
on the current plot.
AXIS AUTO returns the axis scaling to its default, automatic
mode where, for each dimension, ’nice’ limits are chosen based
on the extents of all line, surface, patch, and image children.
AXIS TIGHT
sets the axis limits to the range of the data.
AXIS EQUAL sets the aspect ratio so that equal tick mark
increments on the x-,y- and z-axis are equal in size. This
makes SPHERE(25) look like a sphere, instead of an ellipsoid.
AXIS IMAGE is the same as AXIS EQUAL except that the plot
box fits tightly around the data.
AXIS SQUARE
makes the current axis box square in size.
AXIS NORMAL restores the current axis box to full size and
removes any restrictions on the scaling of the units.
This undoes the effects of AXIS SQUARE and AXIS EQUAL.
AXIS OFF turns off all axis labeling, tick marks and background.
AXIS ON turns axis labeling, tick marks and background back on.
Lecture 4 : MATLAB’s M-files
Chapter 4
4.1
Script m-files
MATLAB’s M-files
MATLAB allows the user to write script files (‘m-files’) to simplify the implementation of complicated algorithms. Example:
%.This.is.the.script.file.‘trigplot’.
%.It.draws.a.graph.of.sin(t),.cos(t).and.sin(t)*cos(t).
t.=.linspace(0,2*pi);
y1=sin(t);
y2=cos(t);
y3=y1.*y2;
plot(t,y1,’-’,t,y2,’.’,t,y3,’--’);
axis([0.2*pi.-1.5.1.5]);
legend(’sin(\theta)’,’cos(\theta)’,’sin(\theta)*cos(\theta)’);
1.5
sin(θ)
cos(θ)
sin(θ)*cos(θ)
1
0.5
0
−0.5
−1
−1.5
0
1
2
3
4
5
6
The script file is executed by entering the name of the file, and it evaluates the
lines of the file one by one as if you typed them in the command window.
25
26
COMO 102: Lecture 4, 2003
4.2
Function m-files
One limitation of script files is their inability to take parameters that modify their
behaviour. To do this MATLAB allows specification of function m-files. E.g.
function.[.cms.].=.inchconv(.inches.)
%INCHCONV.Converts.a.measurement.in.inches.to.centimeters.
%..Based.on.1.inch.=.2.54.centimeters.
cms.=.2.54.*.inches;
• The first line (the function declaration) defines the input and output values
and specifies the function name. The name of the function (inchconv here)
should ALWAYS match the filename!
• The comment lines, those starting with the % symbol, describe the function.
Comments immediately following the function declaration appear when help
functionname is called (help inchconv in this case).
• The remaining lines perform operations on the input matrices. We have one
input matrix here - inches, and one output matrix - cms.
• Examples of calling this routine are:
>> inchconv(1)
ans =
2.5400
>> inchconv(253.1234)
ans =
642.9334
>> inchconv([ 1 2 3; 4 5 6])
ans =
2.5400
5.0800
7.6200
10.1600
12.7000
15.2400
>> help inchconv
INCHCONV Converts a measurement in inches to centimeters.
Based on 1 inch = 2.54 centimeters.
We could easily modify this routine to convert to other units1 , e.g. :
• 1 inch = 100 caliber (gun barrel caliber)
• 1 inch = 0.00001716 roman miles
• 1 inch = 8.23E-19 parsecs (where E-19 means ∗10−19 )
• 1 inch = 0.11111111 span (cloth span)
• 1 inch = 0.00023148 skein
• 1 inch = 1.14 finger
1
Courtesy of www.convertit.com.
27
COMO 102: Lecture 4, 2003
4.2.1
plotData - A More Complicated Example
function.plotData(fname)
%.plotData...Plot.(x,y).data.from.columns.of.an.external.file
%
%.Input:.....fname.=.(string).name,.including.extension,.of.the.
%....................file.containing.data.to.be.plotted
data.=.load(fname);....%..load.contents.of.file.into.data.matrix..
x.=.data(:,1);.........%..x.and.y.are.in.first.two.columns.of.data
y.=.data(:,2);
plot(x,y,’o’);
This loads data from the given file of the form:
first_x_value
second_x_value
third_x_value
..etc..
first_y_value
second_y_value
third_y_value
..etc..
An example usage is:
>> plotData(’xy.dat’);
which yields:
6
4
2
0
−2
−4
−6
4.2.2
0
1
2
3
4
5
6
7
8
Use of Subfunctions
MATLAB version 6 allows us to define subfunctions within one m-file (although
Octave, a free equivalent of MATLAB, does not). The subfunctions are hidden to
everything outside the m-file, and cannot be called from the command window. An
example follows, which calculates the area and perimeter of an n-sided polygon with
‘radius’ r.
28
COMO 102: Lecture 4, 2003
s
r
θ
a = 21 nr2 sin
p = 2nr sin
π
n
s = 2r sin
π
n
2π
n
n=6
function.[a,p].=.polyGeom(n,r)
%.polyGeom..Compute.area.and.perimeter.of.a.regular.polygon
%
%.Input:..r.=.radius.of.smallest.enclosing.circle
%.........n.=.number.of.sides.of.the.polygon
%
%.Output:.a.=.total.area.of.the.polygon
%.........p.=.total.perimeter.of.the.polygon
a.=.area(r,n);
p.=.perimeter(r,n);
%.============.subfunction."area"
function.a.=.area(r,n)
%.Computes.the.area.of.an.n-sided.polygon.of.radius.r
a.=.0.5*n*r^2*sin(2*pi/n);
%.============.subfunction."perimeter"
function.p.=.perimeter(r,n)
%.Computes.the.perimeter.of.an.n-sided.polygon.of.radius.r
p.=.n*2*r*sin(pi/n);
Examples using polyGeom:
>> [a,p]=polyGeom(4,sqrt(2))
a = 4.0000
p = 8
>> [a,p]=polyGeom(6,1)
a = 2.5981
p = 6.0000
>> [a,p]=polyGeom(6,2)
a = 10.3923
p = 12.0000
COMO 102: Lecture 4, 2003
4.3
Flow Control: If statements and for loops
An example illustrating if statements and for loops follows.
function.[.C.].=.addmtx(.A,.B)
%ADDMTX.-.adds.the.matrix.A.to.the.matrix.B,.returning.C.
%..A.slow.and.inefficient.way.to.add.matrices.-.uses.loops.
if.(any(size(A)~=size(B)))..%.Do.both.dimensions.agree?.If.not...
....disp(’The.matrices.are.not.of.the.same.size!’);
....return;
end;
[m,n]=size(A);...%.which.is.the.same.as.size(B).
C.=.zeros(m,n);..%.MATLAB.can.enlarge.matrices.as.we.add.elements
.................%.but.its.very.slow,.so.we.initialise.the.matrix.
for.i=1:m
....for.j=1:n
........C(i,j)=A(i,j)+B(i,j);
....end
end
%.we’re.done!.C.will.be.returned.when.the.function.is.called.
We test the routine as follows:
>> A=reshape([1:9],3,3)’;
>> B=reshape([-5:3],3,3)’;
>> addmtx(A,B)
ans =
-4
2
8
-2
4
10
0
6
12
-2
4
10
0
6
12
>> A+B
ans =
-4
2
8
29
COMO 102: Lecture 4, 2003
4.3.1
30
Relational Operators
MATLAB uses 0 to represent ‘false’, and any non-zero number (often 1) to represent ‘true’. Examples of relational operators are:
>> 2<4
% 2 is less than four...
ans =
1
% true.
>> %------------------------------------------------->> 2>4
% 2 is greater than four...
ans =
0
% false.
>> %------------------------------------------------->> 2==4
% 2 is equal to four...
ans =
0
>> %------------------------------------------------->> 2~=4
% 2 is NOT (~) equal to four...
ans =
1
>> %------------------------------------------------->> 2<4 & 2>4
% 2<4 AND (&) 2>4
ans =
0
>> %------------------------------------------------->> 2<4 | 2>4
% 2<4 OR (|) 2>4
ans =
1
>> %------------------------------------------------->> 2<4 & ~(2>4)
ans =
1
31
COMO 102: Lecture 4, 2003
These operators can of course be used on vectors and matrices:
>> A=[1:9]
A =
1
2
3
4
5
6
7
8
9
1
1
1
0
0
0
0
0
-1
1
3
5
7
9
11
13
0
0
0
0
1
1
1
1
>> A<5
ans =
1
>> B=[-3:2:13]
B =
-3
>> A<B
ans =
0
We can then use the built-in logical functions such as:
• all(X) - true if all elements of X are non-zero (true).
• any(X) - true if any elements of X are non-zero (true).
• isreal(X) - true if X only has real (non-complex) elements.
For example:
>> all(A<B) % is every element in A less than the corresponding element in B?
ans =
0
>> any(A<B) % are any elements in A less than the corresponding element in B?
ans =
1
32
COMO 102: Lecture 4, 2003
4.3.2
The if statement in MATLAB
The if command takes the following form:
if (expression )
...
elseif (expression )
...
else
...
end
for example:
if.(i<0)
........disp(’i.is.less.than.zero.’);
........%.can.have.more.commands.here...
elseif.(i==0)
........disp(’i.is.equal.to.zero.’);
else
........disp(’i.is.greater.than.zero.’);
end
4.3.3
Using for loops in MATLAB
The basic format of a for loop is:
for variable = vector
...
end
The for loop executes the block of statements once for each element of the vector
in turn, with the variable assigned to the current element.
octave:1> y=0;
octave:2> for x=[1 2 9 10]; y=y+x; end;
octave:3> y
y = 22
More normally it is used with the colon notation, e.g.
%.a.script.m-file.showing.for.loops.
y.=.zeros(1,12);
y(1)=1;.y(2)=1;
for.x=3:12
.....y(x).=.y(x-1).+.y(x-2);
end
disp(y);
octave:1> addition
1
1
2
3
5
8
13
21
34
55
89
144
Lecture 5 : Differential Equations:
Chapter 5 Euler’s Method
Differential Equations: Euler’s
Method
5.1 Derivatives
Covered on the whiteboard:
1. Derivatives as limits.
2. Derivatives and integrals.
3. Differential equations.
5.2
Introduction: ODEs
In this lecture we consider first order ordinary differential equations (ODEs) of the
form
dy
= f (t, y)
(5.1)
dt
where f (t, y) is a function of the independent variable t and the dependent variable
an ordinary derivative as y is a function of t alone1 . Equation (7.1)
y. We call dy
dt
gives an expression f (t, y) representing the rate of change of the dependent variable
y with respect to the independent variable t. Geometrically we can think of this as
an equation specifying the slope of the graph at each point in terms of it’s position,
with the position to be determined from this information.
Equation (5.1) does not completely specify y(t). In fact, it has an infinite number
of solutions. To specify a unique y(t) we must also have an initial condition, such
as
y(t0 ) = y0 .
The initial condition is usually written together with the differential equation to
form an initial value problem, i.e.
dy
= f (t, y),
dt
y(t0 ) = y0 .
(5.2)
We may also specify a range of t over which the equation is to be solved (e.g.
t0 ≤ t ≤ tN ). Note that we use t as our independent variable, implying that
1
Partial differential equations have functions of two or more variables, and involve ‘partial’
derivatives (derivatives evaluated by holding all but one variable fixed).
33
34
COMO 102: Lecture 5, 2003
our problem is time dependent. The independent variable could just as easily be x
(implying a position dependent problem), or represent some other quantity entirely.
In the case of x as the independent variable, the ‘initial’ value can is placed on a
boundary of the domain, often at x = 0.
Equation 5.2 represents a first order ODE because the highest derivative is of
first order. Ordinary differential equations exist with second, third and higher order
derivatives. We can also have coupled systems of differential equations, i.e. several
equations and initial conditions of the type shown in Equation (5.2), each with it’s
own dependent variable, which is dependent on the other dependent variables as
well as the independent variable. For example, a simple system of coupled ODEs is
given by:
dy1
= αy1 + βy2 + g1 (t),
dt
dy2
= γy1 + δy2 + g2 (t),
dt
y1 (t0 ) = y1,0 ,
y2 (t0 ) = y2,0 .
Here α, β, γ and δ are given coefficients (i.e. we know what they are when we begin
to solve the problem), and g1 (t) and g2 (t) are known functions of t.
The numerical methods we will discuss are primarily designed for solving firstorder ODEs. Higher order ODEs can be solved numerically by first converting them
into a mathematically equivalent system of coupled, first-order ODEs2 .
5.2.1
Example: Newton’s Law of Motion as an ODE
Recall that the one-dimensional motion of an object under the action of an applied
force is governed by
F = ma
where F is the magnitude of the force, m the mass of the object, and a its acceleration.
Consider the case where the force F is varied with time, so that F = F (t). We
can formulate the problem with either displacement or velocity as the dependent
variable. Displacement will lead to a second order ODE, and velocity a first order
ODE.
Velocity as the Dependent Variable
Consider velocity as the dependent variable, where a =
dv
dt
and so
F (t)
dv
=
.
dt
m
If the function F (t) is known, as is the velocity at some time t0 , then this equation
can be integrated to find v(t). More interesting problems have F dependent on v,
t and other parameters rather than just on t.
2
This is done by introducing new variables representing the derivatives, thus producing the
system of coupled differential equations.
35
COMO 102: Lecture 5, 2003
5.2.2
Example: Newton’s Law of Cooling
Consider the situation shown in the following figure.
T∞
Ts
m, c
An object of surface temperature Ts , mass m and ‘specific heat’ c is immersed
in fluid which flows over the object cooling it. The fluid temperature away from
the object is labelled T∞ , and Newton postulated that the rate at which heat is
exchanged between object and fluid is proportional to the difference between Ts
and T∞ , i.e.
Q = HA(Ts − T∞ ),
where Q is the instantaneous heat transfer rate, H is the ‘heat transfer coefficient’,
and A is the surface area of the object.
This equation can be substituted into an equation for the conservation of energy
of the system. If we assume that heat travels quickly through the object, so that
the instantaneous temperature of the object T is assumed to be equal everywhere
in the object to the surface temperature Ts , then we have
mc
dT
= −Q = −HA(T − T∞ ),
dt
which gives us
dT
HA
=−
(T − T∞ ) .
dt
mc
This equation is now in the form of Equation (5.1). It is linear, so may be solved
directly, but is also suitable for numerical analysis.
36
COMO 102: Lecture 5, 2003
5.3
Strategy for the Numerical Methods
Our goal is to find a numerical approximation to y(t) given an initial value problem
of the form of Equation (5.2). We can write
y(t) = y0 +
Z
t
t0
f (t̃, y) dt̃,
so that the solution to Equation (5.2) can be thought of as the evaluation of an
integral.
An ODE of the form dy
= f (t) can be integrated with standard numerical
dt
integration techniques, such as Gaussian Quadrature, Newton-Cotes Rules, etc.
However if f = f (t, y) then more advanced methods are needed, as will be discussed
here.
The general idea is to start at the given initial value, evaluate the integral over
a short time step, move to a new estimated position, evaluate the integral there,
move to a new estimated position, and so on.
Thus the numerical solution to Equation (5.2) is only obtained at a finite number
of t values. The numerical solution is therefore said to be discrete as opposed to
the exact solution y(t) which is continuous.
Let the sequence of discrete time values, that we will produce an approximate
numerical solution to y(t) at, be given by
tj = t0 + jh,
j = 0, 1, 2, . . . , N,
where the spacing parameter h is called the stepsize. The basic techniques use a
constant value of h for the entire process, while more advanced methods adapt the
value of h to the local behaviour of the solution, using smaller stepsize where the
value of the function changes rapidly (“adaptive” methods).
The numerical solution to Equation (5.2) is obtained by producing a series of
yj values at the corresponding tj , where yj ≈ y(tj ). Recall that y(tj ) is the exact
solution evaluated at t = tj . We can write the error in the numerical solution at tj
as
ej = yj − y(tj ).
37
COMO 102: Lecture 5, 2003
5.4
Euler’s Method
Euler’s method is based on a “Taylor Series” expansion of y(t). A Taylor Series
is a way of writing a function as an infinite polynomial, and is useful in producing approximations to the function using a simple expression. The Taylor Series
expansion of y(t) about t = t0 is:
y(t) = y(t0 ) + (t − t0 )y 0 (t0 ) +
(t − t0 )2 00
y (t0 ) + . . . ,
2
where y 0 is the first derivative of y, and y 00 is the second derivative. If t and t0 are
very close together then |t − t0 | << 1, and the higher order terms are negligible,
giving us
y(t) ≈ y(t0 ) + (t − t0 ) y 0 (t0 )
= y(t0 ) + (t − t0 ) f (t0 , y0 ),
since y 0 (t0 ) = f (t0 , y0 ) by Equation (5.1). We can use this to calculate y1 ≈ y(t1 )
in terms of y0 :
y1 = y0 + h f (t0 , y0 ),
where h = (t1 − t0 ). The same procedure can produce y2 :
y2 = y1 + h f (t1 , y1 ),
and so forth.
5.4.1
Euler’s Method is a series of Straight Line Approximations
It may not surprise you to learn that Euler’s method is just a series of straight line
approximations to the to the exact solution. (This is demonstrated in the lecture
on the white-board).
Lecture
Chapter6 :6Programming in MATLAB:
The Asteroid Problem
Programming in MATLAB: The
Asteroid Problem
6.1
An Asteroid under Earth’s Gravity
A group of astronomers have just returned from their lunch break, and notice a
previously unseen asteroid hurtling towards the Earth. They telephone you, and
ask if the asteroid will impact the planet or narrowly miss. During the conversation
you learn that:
• The radius of the Earth is 6378 km, and its mass is 5.972 · 1024 kg.
• The approach is planar (i.e. the path of the asteroid lies in a plane), so the
problem can be modelled in two dimensions.
• Choosing a coordinate system so that the Earth is positioned at the origin,
the asteroid is currently at x = 20, 000km and y = 20, 000km.
• The asteroids velocity is currently parallel to the x-axis, and its speed is
between 3 and 5 km s−1 .
• The magnitude of the gravitational force between two bodies is given by
|F~ | =
GM m
,
r2
where G is the universal gravitational constant (G = 6.672 · 10−11 Nm2 kg−2 ),
M is the mass of the first body (the Earth), m the mass of the second body
(the asteroid), and r the distance between them.
Describing the path of the asteroid analytically is difficult, so you approximate its
path using Euler’s method. The independent variable is time (t), and the initial
position of the asteroid is at t0 = 0. You write the step size as h = ∆t , so that
Euler’s method will give the asteroid’s position at times t = 0, ∆t , 2∆t , 3∆t , . . ..
The calculation will continue until either the asteroid has impacted the Earth or
escaped the solar system.
38
39
COMO 102: Lecture 6, 2003
Asteroid at time t = 2∆t (third position).
Asteroid at time t = ∆t (second position).
Asteroid at time t = 0.
Asteroid at time t = 0.
Asteroid at time t = n∆t .
We calculate each position in turn. The asteroid’s position and velocity at t = ∆t is
calculated from its position, velocity and acceleration at t = 0. Then the asteroid’s
position and velocity at t = 2∆t can be calculated from its position, velocity and
acceleration (which is easily determined) at t = ∆t . This process continues until
we reach t = n∆t for some large n, and we have then found the asteroids path.
6.2
One Step of the Asteroids Motion
At time t = i · ∆t , let the vector ~xi be the asteroids position, ~vi be its velocity and
~ai be its acceleration. Choose our coordinate system so that the Earth is at the
origin. Then we have the following situation.
~vi+1
Asteroid at time (i + 1) · ∆t
~vi
~ai+1
Asteroid at time i · ∆t
~ai
~xi+1
~xi
The Earth
40
COMO 102: Lecture 6, 2003
6.2.1
Calculating the Acceleration Vector
The acceleration vector can be written in terms of its magnitude multiplied by a
unit direction vector (giving the direction and sense of the acceleration vector), i.e.
~a
∗
~a =
|~a|
(6.1)
|{z}
|~a|
|{z}
magnitude
direction
The magnitude of the acceleration vector can be found using Newton’s Law:
F~ = m~a ⇒ |F~ | = m |~a|
(6.2)
And the magnitude of the gravitational force, |F~ |, for two bodies (with masses M
and m) a distance r apart is:
GM m
|F~ | =
.
(6.3)
r2
Substituting Eq. 6.3 into Eq. 6.2 we have the following (where r = |xi | because the
centre of the Earth is at the origin).
GM m
GM
GM
=
m
|~
a
|
⇒
|~
a
|
=
=
.
(6.4)
r2
r2
|~xi |2
Thus the gravitational acceleration of the asteroid due to the Earth is independent
of the mass of the asteroid!
The acceleration vectors always points towards the centre of the Earth (why is
this so?). Then referring back to the diagram we see that ~ai has the same direction
and sense as −~xi . In terms of unit vectors we have
~xi
~ai
=−
.
(6.5)
|~ai |
|~xi |
This tells us the orientation of the acceleration vector (the direction of the acceleration). Substituting Eq. 6.4 and Eq. 6.5 into Eq. 6.1 yields
~ai =
Thus
GM
|~xi |2
!
~ai = −~xi
6.2.2
!
~xi
−
.
|~xi |
GM
|~xi |3
Calculating the New Position and Velocity
Under constant acceleration the new velocity is easily found:
d~v
= ~a , so from Euler’s method, ~vi+1 = ~vi + ∆t ~ai
dt
Similarly the velocity will be nearly constant over the small time interval ∆t , and
so Euler’s method gives
~xi+1 = ~xi + ∆t ~vi .
This gives us iterative equations for the approximated position and velocity:
~vi+1 = ~vi + ~ai ∆t ,
~xi+1 = ~xi + ~vi ∆t
41
COMO 102: Lecture 6, 2003
6.2.3
An Algorithm to Solve the Asteroid Problem
1. Choose the number of steps n and the time interval per step ∆t .
2. Initialize matrices X and V (both with n + 1 rows and 2 columns).
3. Choose a starting position vector ~x0 and velocity vector ~v0 for the asteroid.
4. Set the first row of X to be ~x0 , and the first row of V to be ~v0 .
5. Set i = 0.
6. While i < n repeatedly do the following:
(a) Calculate ~ai using
~ai = −~xi
(b) Calculate ~vi+1 and ~xi+1 using
~vi+1 = ~vi + ~ai ∆t ,
GM
|~xi |3
~xi+1 = ~xi + ~vi ∆t
(c) Store ~xi+1 in row i + 2 of X and ~vi+1 in row i + 2 of V.
(d) If |~xi+1 | < 6378km display ”Impact with Earth!” message, impact velocity and time, then terminate.
(e) Let i = i + 1.
7. Output or graph the positions stored in X and the velocities stored in V .
For example, with an initial velocity of 5 km · s−1 , we get:
7
x 10
2
1
y position (metres)
0
−1
−2
−3
−4
−5
−4
−3
−2
−1
0
1
x position (metres)
2
3
4
7
x 10
42
COMO 102: Lecture 6, 2003
6.2.4
Errors
Clearly there are small errors associated with using Euler’s method, which amounts
to assuming that the derivatives of the dependent variables (position and velocity)
are constant over the small time steps. These errors build on one another, slowly
pushing the calculated path further and further away from the true solution. The
graph below shows two paths, one more accurate than the other.
7
x 10
2
1
y position (metres)
0
−1
−2
−3
−4
−5
−4
−3
−2
−1
0
1
x position (metres)
2
3
4
7
x 10
• Which path is the more accurate of the two?
• How can we improve the accuracy of a path that is calculated using the above
approach?
• Can you think of a scheme which would iterate, at each step finding a successively more accurate approximated path, and stop when we have found a
path with sufficient accuracy?
43
COMO 102: Lecture 6, 2003
6.3
Multiple Planets
Planet 1
Planet 2
F~1
F~total
F~2
F~3
= F~1 + F~2 + F~3
Planet 3
When considering multiple planets the total force on the asteroid due to the planets
is just the sum of the individual force vectors. Similarly the total acceleration is
just the sum of the acceleration vector for each planet!
Planet
~a
p
~
~x
Asteroid
If we consider a planet at position p~ with mass M and the asteroid at position ~x
then the acceleration of the asteroid due to that planet is:
~a = (~
p − ~x)
GM
r3
where
r = |~
p − ~x|.
44
COMO 102: Lecture 6, 2003
6.3.1
Three Planets
For example, the m-file “threeplanets.m” on COMO produces the following image:
>> threeplanets
COLLISION WITH PLANET!
Impact velocity is 10902.360138 m/s.
Time is t=98150.000000 seconds.
7
Trajectory of Asteroid
x 10
2
venus
1
earth
0
metres
−1
mars
−2
−3
−4
−5
−6
−6
−4
−2
0
metres
2
4
7
x 10
Lecture 7 : Various Topics
Chapter 7
7.1
Revision
Various
Topics
In the last lecture we considered first order ordinary differential equations (ODEs)
of the form
dy
= f (t, y)
(7.1)
dt
where f (t, y) is a function of the independent variable t and the dependent variable
y.
The differential equation is usually written together with an initial condition to
form an initial value problem, i.e.
dy
= f (t, y),
dt
7.1.1
y(t0 ) = y0 .
(7.2)
Strategy for the Numerical Methods
Our goal is to find a numerical approximation to y(t) given an initial value problem
of the form of Equation (7.2). The general idea is to start at the given initial value,
then at each iteration we calculate the slope at the current value, and move a short
ways in a direction determined by the slope to arrive at the next value.
The numerical solution to Equation (7.2) is obtained only at a finite number of
t values (i.e. the numerical solution discrete as opposed to the continuous exact
solution y(t)).
45
46
COMO 102: Lecture 7, 2003
7.1.2
Euler’s Method
As we have seen, Euler’s method is a simple way of numerically solving Equation (7.2). At each iteration, Euler’s method uses the tangent line to the curve to
calculate the next value.
y
Exact
Solution
Approximate
Solution
t
We saw in the last exercise that Euler’s method produces more accurate approximations to the true solution y(t) as we decrease the ‘step size’ h.
1
h=0.2
h=0.1
h=0.05
Exact
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
However, the smaller we choose h to be, the greater the number of calculated points,
and the longer it takes for us to generate our numerical solution. Higher accuracy
methods, which require fewer calculations to produce a solution with a given accuracy, generally choose the next point at each iteration in a more sophisticated way.
Can you think of a modification to Euler’s method that would improve accuracy?
COMO 102: Lecture 7, 2003
7.2
47
ode23 and ode45
Unsurprisingly MATLAB contains sophisticated, fast and accurate ODE IVP solvers.
There are many ways to improve upon Euler’s method; adaptive choices of step size
(using smaller steps where the function is changing rapidly), higher order approximations, and switching between combinations of methods as necessary all provide
significant performance and accuracy gains. MATLAB has entire toolboxes devoted
to the solutions of differential equations, and can be used to solve a wide variety of
problems. The basic workhorse routines are ode23 and ode45, which can be used
as direct replacements (with one minor change) for your odeEuler routine from the
last exercise.
7.2.1
ode23
ODE23 Solve non-stiff differential equations, low order method.
[T,Y] = ODE23(ODEFUN,TSPAN,Y0) with TSPAN = [T0 TFINAL] integrates the
system of differential equations y’ = f(t,y) from time T0 to TFINAL with
initial conditions Y0. Function ODEFUN(T,Y) must return a column vector
corresponding to f(t,y). Each row in the solution array Y corresponds to
a time returned in the column vector T. To obtain solutions at specific
times T0,T1,...,TFINAL (all increasing or all decreasing), use
TSPAN = [T0 T1 ... TFINAL].
To solve the question in the exercise, where y 0 (t) = t − 2y, we could use the
following “ODEFUN” function:
function dydt = myodefun(t,y)
dydt = t - 2*y;
Lets assume we are interested in 0 ≤ t ≤ 10, and at t = 0 we have the initial
condition that y = 1. We can then call ode23 and plot the result with the following
code:
[t,y] = ode23( ’myodefun’, [0, 10], 1 );
plot(t,y);
Note that we do not need to specify a step size, h. This is because ode23 chooses
appropriate step sizes as necessary. We can use the TSPAN = [T0 T1 ... TFINAL]
form to force it to use a given step size; for example we could force h = 0.2 by
replacing the [0, 10] in the above code with 0:0.2:10.
7.2.2
ODE45
ode45
Solve non-stiff differential equations, medium order method.
COMO 102: Lecture 7, 2003
7.3
48
File Input and Output (“I/O”) in MATLAB
The ability to save and restore your calculated or entered data is a crucial part of
scientific programming. This also allows you to import and export data, enabling
you to use MATLAB together with other software.
7.3.1
ASCII and MAT files
MATLAB has simple routines for loading and saving “MAT” binary files (MATLABonly format) and “ASCII” text files (readable and writable by many programs).
MAT loading and saving
To save a variable myvar to the file filename.mat you can issue the command:
save filename myvar
If the variable name is omitted (i.e. you just type save filename) then all the
current workspace variables are saved together in the one file! You can save multiple
variables of your choosing in one file by issuing
save filename variable1 variable2 ...
Once you have saved myvar in the file filename.mat you can load myvar in
another MATLAB session by entering:
load filename
There is no need to specify the variable name (myvar) - MATLAB will load all the
variables stored in filename.mat automatically.
ASCII loading and saving
To save an ASCII file we use save as above, but with the addition of -ascii at the
end of the line, and we save it as a filename.txt. For example:
>>
>>
>>
>>
x = 0:5; y = 5*x;
XY = [x’ y’];
save xyvals.txt XY -ascii
type xyvals.txt
0.0000000e+000
1.0000000e+000
2.0000000e+000
3.0000000e+000
4.0000000e+000
5.0000000e+000
0.0000000e+000
5.0000000e+000
1.0000000e+001
1.5000000e+001
2.0000000e+001
2.5000000e+001
Note that the numbers are saved in scientific format, e.g. 15 is written as 1.5000000e+001.
To load this file we use the ‘load’ command:
>> load -ascii xyvals.txt
The results are stored in a new variable of the same name as the file (xyvals here).
49
COMO 102: Lecture 7, 2003
7.4
Machine Precision
Consider the following code fragment:
epsilon.=.1;
while.(..1.+.epsilon..~=..1..).
....epsilon.=.epsilon./.2;
end
disp(epsilon);
Imagine a perfectly accurate computer. On such a machine this routine would
run forever, with getting smaller and smaller but never reaching zero (so that 1+
is never equal to one). This is also true for symbolic packages, as they are able to
perform exact arithmetic. However, computer languages and packages are usually
designed to store numbers as a series of decimal digits (the mantissa) combined
with a factor of 10n (n is the exponent). For example, π might be stored as:
3.14159265358979 ∗ 100 .
This is merely an approximation of π, as π is an irrational number and can not be
written exactly using a finite number of digits.
If we restrict ourselves to a fixed number of mantissa digits then we are effectively
approximating the real number line with a series of discrete points. The computer
is unable to distinguish between two real numbers very close together, and they are
stored as the same value. The code listed above illustrates this by finding a value
of for which MATLAB is unable to distinguish between 1 and 1 + . With the
default MATLAB settings this value turns out to be 1.1102 ∗ 10−16, which may seem
small enough to neglect but in some circumstances can be significant!
The machine precision is the largest number m such that
1.0 + δ = 1.0,
whenever
|δ| < m
Thus we know that the default machine precision in MATLAB is larger1 than
1.1102 ∗ 10−16 .
Mathematically, the equation 1.0 + δ = 1.0 has only the solution δ = 0, so that
m is identically equal to zero. But, because computers use floating-point arithmetic
and not exact arithmetic, m > 0 for numbers stored on a computer.
7.4.1
Consequences
The real problems arise when performing a large number of operations, or operations
that rely on the least significant digits of numbers. For example, consider the
following:
1
Q: Why larger? Why is it not equal to 1.1102 ∗ 10−16 ?
COMO 102: Lecture 7, 2003
50
>> 10000000000000009999 - 10000000000000000000
ans =
10240
>> 10000000000000000000 + 10240
ans =
1.0000e+019
Clearly, when implementing numerical algorithms, it will always pay to consider
whether there will be any serious subtractive cancellation or particular sensitivity
to round-off error. These problems can often be avoided by algebraic rearrangement
of the expressions being evaluated.
Other problems can arise when we reach the limits of the exponent. Because the
exponent must be stored using a fixed number of digits, we have a corresponding
maximum and minimum number that can be entered. In MATLAB numbers as big
as 10309 are indistinguishable from ∞:
>> 10^308
ans =
1.0000e+308
>> 10^309
ans =
Inf
This behaviour is called “overflow”. Similarly we have “underflow”, where the
exponent is negative and so large in magnitude that it can not be stored:
>> 10^(-324)
ans =
0
Avoiding over- and underflow is also important when considering how to enter an
expression. Often some simple rearrangement (producing mathematically identical
expressions) can have drastic effects on accuracy when entered in a computer!
51
COMO 102: Lecture 7, 2003
7.4.2
Example: Modulus of a complex number
Mathematically we write the modulus of a complex number x + i y as:
|x + i y| =
q
x2 + y 2 .
Entering it in this form on computer is generally a bad idea, because for large x the
x2 term can easily ‘overflow’. A simple rearrangement can pull out a factor x:
q
x2
+
y2
=
=
v
u
u
tx2
√
x2
y2
1+ 2
x
s
s
1+
= |x| 1 +
!
2
y
x
2
y
x
and similarly we can pull out a factor of y:
q
x2 + y 2 = |y|
v
u
u
t
x
1+
y
!2
.
These forms can fail if the denominator is zero, and cause overflow if the denominator is extremely small, so if |x| > |y| we use the first expression, and if |y| > |x|
we use the second.
Question: why are we less concerned about underflow?
Lecture 8 : Programming in C
Chapter
8
A list of some of the C resources on the internet can be found at:
http://www.lysator.liu.se/c/c-www.html
Programming in C
8.1
Basic Concepts
A computer is told what to do by programs written by humans. This means a programming language must both be understandable for people and easily translatable
to the basic computer instructions (“machine code”).
A programming language, like any other language, has rules about structure, use
of words and spelling. The big difference between human and computer language
is that a computer cannot guess what is meant if an error is made. Therefore, rules
in a computer language are very strict.
8.1.1
Statements
A program consists of simple, basic instructions called statements. These statements perform the basic tasks such as performing calculations and outputting results to the screen.
8.1.2
Data and variables
Of course, statements alone do not make a program; data must be imported,
checked, manipulated and stored. This is done by the use of variables. A variable is a certain part of memory that has been given a name and in which data can
be saved, by assigning a value through the variable-name. For example,
a = 5 + 3;
would result in the memory address with the label a storing the value 8.
Just like in MATLAB, variables can be used to assign values to other variables, e.g.
a = 3;
c = 5 * a;
would result in a storing the value 3, and c storing 15.
52
COMO 102: Lecture 8, 2003
8.1.3
53
Declarations
Like in many languages, a C programmer must inform the computer of the names
of the variables and their types. There are several distinct types for variables,
including int (integers), double (double precision floating point numbers), and
char (characters).
Additionally, the procedures and functions to be used must be declared - the
programmer states the names of the procedures and functions, the input parameters that they require and the type of the value each returns. The variables and
procedures are declared before their use.
8.1.4
Pointers
Depending on the type of the data, a variable can be a number, a string of characters,
or something more complicated. Pointers are a special type of variable because they
do not store a directly useful value but instead point to the memory address in which
such a value is stored. At first this seems unnecessary - why do we care where the
data is stored? However we shall see that there are some cases where pointers are
very useful.
Pointers are one of the strengths of C. They also are the cause of many catastrophic bugs in C programs, largely because they allow direct modification of memory contents with only minimal error checking. Pointers allow very flexible data
structures to be created, from simple binary trees and linked lists to large customised structures tailored to a specific application.
Without pointers C is very limited. For example, a maximum size for every
matrix that is used must be specified ahead of time, and functions can only modify
a single variable. While C++ has a few nice ways to get around these problems,
we’ll be sticking to straight C in this course and so we need to know a little about
pointers. Their introduction will be gentle, but you’ll need to keep your wits about
you whenever you use them.
8.1.5
Arrays
If you want to use many variables of the same type for the same purpose, you
could, of course, declare them all separately: a1, a2, a3, a4... However there is a
better way for dealing with this; by using arrays. These are sequences of a number
of variables of the same type, addressed by one single name. The selection of the
specific variable from the sequence is done using an integer index. For example, if
d is an array, d[0] would address the first element, d[1] the second, etc. There is
another great advantage in arrays - you can use calculations to determine which
element is to be used.
COMO 102: Lecture 8, 2003
54
For example, consider the following code, which stores the value 501 in all of
the even elements of myarray from 0 to 20. What value do you think will be stored
in the odd elements?
int myarray[21];
for (index = 0; index <= 10; index++)
myarray[index * 2] = 501;
It is not hard to imagine what this code would look like if you had to change all those
entries one by one! An important thing to note here is that arrays are indexed starting at zero not one (i.e. the first entry in myarray is myarray[0] not myarray[1]).
Thus the declaration int myarray[21]; creates an array called myarray that holds
21 elements, indexed from myarray[0] through to myarray[20].
Higher dimensional arrays are allowed; if d is declared as a two-dimensional
array one could access d[0][0] and d[0][1] (first two elements from the first row of
the corresponding ‘matrix’), but also d[2][0] and d[2][1] for example (from the third
row). Arrays of higher dimensions are also allowed.
It should be clear that these one dimensional arrays are closely related to vectors,
and two dimensional arrays are closely related to matrices. Unlike MATLAB, C
has no inbuilt matrix or vectorised operations, and manipulation of arrays is often
performed using loops (for loops, while loops etc.). While not so obvious, arrays in
C are closely related to pointers. We’ll discuss this more later.
8.1.6
Functions
Like in MATLAB, the C language allows the creation of functions.
• Functions have their own local variables that can’t be accessed outside of the
function!
• Like in MATLAB, C functions are called using their name.
• C has a few inbuilt functions and you can load ‘libraries’ that contain further
commonly used functions (such as sin and fprintf).
• A function can call another function. In most languages, including C, it can
even call itself (this is called recursion)!
• Every C program has a ‘main’ function. This function is automatically called
when the program is run.
8.1.7
Local and global variables
Just like with function m-files in MATLAB, local variables can only be used inside
the function in which they are declared. Outside of that function they do not exist,
and attempts to use them from another function will generate errors.
Global variables, which are defined at the start of the code before the first
function, can be used throughout the whole program. A global variable is available
COMO 102: Lecture 8, 2003
55
to all functions. This sounds convenient, however their use is generally considered
to be a poor programming practice. We’ll avoid global variables in this paper.
8.1.8
Parameters
Functions and procedures often require some input to work, usually a small collection of variables whose values are set in the calling routine. These are called
‘parameters’, and are placed after the name of the function/procedure. The code
a = minimum(3, -1, 4);
would call the function minimum, pass the values 3, -1 and 4 to it and put the
result of the function (-1 in this case) into the variable a.
Minimum might be written like this:
int minimum(int n1, int n2, int n3) {
if (n1<n2 && n1<n3) return n1;
if (n2<n3)
return n2;
return n3;
}
Here minimum is declared to take three parameters, all integers (the type is int),
and return one integer. Note that every parameter is declared to be a particular
type. The curly braces represent the beginning and end of the function.
8.2
A Short History of the Language C
Contrary to most other programming languages the name of the language C is
not the name of a long gone mathematician or the first letters of the words which
describe the language. The reason C is called C is very simple: it’s the successor
of the language ‘B’. B got its name from the place of its origin: Bell Laboratories.
The creator of C worked at the Bell Laboratories as well. As a matter of fact, C is
loosely based on B. The reason they gave a new name to this version rather than
make it a new version of B is that the improvements made were very substantial
and arguably, at the time they were made, revolutionary. These changes were
important enough to keep C alive for over 17 years. This powerful language has
survived several revisions, including the object-orientated C++, and is so valuable
that its demise is not in sight (while B is never heard of anymore).
The first version of C was written and implemented by D.M. Ritchie. It was first
published in The C Programming Language by B.W. Kernighan & D.M. Ritchie
in 1978. Many features of C were very vaguely, or not at all, described at that
time. This caused many incompatible versions of C to be created. Many of these
versions were linked to one certain type of computer, making programs written for
one computer unusable for another.
In 1983, however, the American National Standards Institute (ANSI) founded a
commission (X3J11) to define an unambiguous and computer-independent version
of C. Not so surprisingly, this version was called ANSI C. This version of C has
COMO 102: Lecture 8, 2003
56
some important improvements to the one defined by Ritchie. There are ANSI C
compilers available for virtually any type of computer.
Since the ’release’ of ANSI C, C++ has been developed and has become very
popular. C++ is an object orientated language, with classes, inheritance, and so on.
Most of the structure and style of ANSI C is retained in C++, and a C++ compiler
can be used to compile C programs. You may wonder why we are not learning C++
in this course, given that it is better structured and produces code that is far easier
to reuse. The answer is that C is considerably faster to learn, as there are far fewer
ideas to cover, and without the overhead of an object-orientated language we are
able to quickly write small programs which actually achieve something rather than
spending a great deal of time just setting things up in a nice way.
8.3
8.3.1
A Few Characteristics of the Language C
Compiler-based
C is a compiler-based language. This means that all ’grammatical’ errors must be
out of the program before it will do anything. It also means that it behaves exactly
the same outside the development environment as it does inside.
8.3.2
Extensive Use of Libraries
Standard C on its own only has operators and a very small set of statements such
as if, while and for. Statements to write to the screen and get input from the
keyboard, to retrieve the time and date, work with files, and so forth are not
implemented in standard C. They can be imported with the use of “header files”
and “libraries” of functions.
Advantages:
You can choose your own sets of statements to be ‘embedded’ in the ‘running
versions’ of your programs, keeping those ‘running’ files nice and small.
Disadvantages:
To get the ‘running versions’ running, the library files must either be included in
the executable (“static linking”), or the exact version of the library that was used
when compiling the program must also be available on the computer running the
program (“dynamic linking”).
57
COMO 102: Lecture 8, 2003
8.3.3
Shorthand for symbols that are used often
In many languages every statement, operator and symbol is addressed by a word.
C often uses symbols of only one or two characters for statements that are used
often. MATLAB also has compact notation. For example:
or
and
not
begin
end
8.4
MATLAB
|
&
~
(not used)
end
C
||
&&
!
{
}
Libraries
In C it is possible to cut the source code of a program in pieces. For example,
you can have one file with the main program, one with routines for the screen, one
with routines for files and one for the other routines. These files can be compiled
separately. When a file containing nothing but supporting routines is compiled in
a certain way, this compiled file is called a library.
In order for the compiler to be able to check that you are using the library
routines in the correct manner they need to be “declared”. Clearly only the information from the first line of the routine is needed for this checking, for example,
consider the routine:
int minimum(int a, int b, int c) {
if (a<b && a<c) return a;
if (b<c)
return b;
return c;
}
The first line conveys the important usage information: a routine called ‘minimum’
is declared, which accepts as input three integers, and returns an integer. This
routine can be declared with the line:
int minimum(int a, int b, int c);
Given this information the compiler knows the input and output of the routine, and
can perform error checking in a useful way.
A library consists of many routines, and the list of the declarations for those
routines are contained in a header file. Thus if we are using a library we need to
include the header file in our compilation process so that the compiler knows how
the routines should be used! We will see these ideas in action soon.
COMO 102: Lecture 8, 2003
8.5
8.5.1
58
A Sample C Program
Source Code
/∗.This.is.the.program.wuffwuff.
...The.slash.star.at.the.start.of.the.line.indicates.that.this.is.a.comment.∗/
/∗.First.we.include.the.standard.input/output.library.header,.stdio.h.
...This.library.header.is.needed.to.declare.the.printf.function.............∗/
#include.<stdio.h>
int.plusone(int.a)
{................................/∗.plus.one.adds.one.to.an.integer.........∗/
....int.b;......................../∗.declare.a.local.variable.b,.of.type.int.∗/
....b.=.a.+.1;......................../∗.set.b.to.be.a.plus.1............∗/
....return.b;......................../∗.return.the.value.stored.in.b....∗/
}
int.main(void)
{................................/∗.the.main.routine..∗/
....int.a;......................../∗.declare.a.local.variable.a,.of.type.int..∗/
....printf("Welcome.to.Wuffwuff!\n");......../∗.print.a.message.to.the.screen..∗/
....a.=.7;
....printf("7.+.1.=.%d\n",.plusone(a));......../∗.print.the.output.of.plusone(a).∗/
....return.0;......................../∗.main.always.returns.0..∗/
}
8.5.2
Compilation and Output
[j@bluebox lectures]$ gcc -Wall -o wuffwuff wuffwuff.c
[j@bluebox lectures]$ ./wuffwuff
Welcome to Wuffwuff!
7 + 1 = 8
Lecture 9 : Programming in C Part II
Chapter 9
9.1
Variables in C
Programming
in C Part II
C provides the programmer with FOUR basic data types.
int
float
double
char
-
integer numbers.
floating point numbers (single precision)
floating point numbers (double precision)
a character
User defined variables must be declared before they can be used in a program.
Get into the habit of declaring variables using lowercase characters. Remember that
C is case sensitive, so even though the two variables sum and Sum have the same
name, they are considered to be different variables in C.
9.1.1
Variable Declaration
The declaration of variables is done after the opening brace of main(),
#include <stdio.h>
main()
{
int sum;
sum = 500 + 15;
printf("The sum of 500 and 15 is %d\n", sum);
}
Sample Program Output
The sum of 500 and 15 is 515
It is possible to declare variables elsewhere in a program, but lets start simply and
then get into variations later on. The basic format for declaring variables is
data_type
var, var, ... ;
where data type is one of the four basic types, an integer, character, float, or double
type. The program declares the variable sum to be of type INTEGER (int). The
variable sum is then assigned the value of 500 + 15 by using the assignment operator,
the = sign.
sum = 500 + 15;
59
COMO 102: Lecture 9, 2003
9.1.2
60
Printf
Now lets look more closely at the printf() statement. It has two arguments, separated by a comma. Lets look at the first argument,
"The sum of 500 and 15 is %d\n"
The % sign is a special character in printf statements in C. It is used to display
the value of variables. When the statement is executed, C starts printing the text
until it finds a % character. If it finds one, it looks up the next argument (in this
case sum), displays its value, then continues on. The d character that follows the
% indicates that an integer is expected. So, when the %d sign is reached, the next
argument to the printf() routine is looked up and displayed (in this case the
variable sum, which is 515). The \n is then executed which prints the newline
character. .
9.1.3
Formatting Arguments of Printf
Some of the formatters for printf are,
Cursor Control Formatters
\n newline
\t tab
\r carriage return
\f form feed
Variable Formatters
%d integer
%c character
%s string or character array
%f float
%e double
The following program prints out two integer values separated by a TAB. It does
this by using the \t cursor control formatter.
#include.<stdio.h>
int.main()
{
....int.sum,.value;
....sum.=.10;
....value.=.15;
....printf("%d\t%d\n",.sum,.value);
....return.0;.................../∗.normal.termination.∗/
}
COMO 102: Lecture 9, 2003
[j@aythya lectures]$ gcc sumvalue.c -o sumvalue
[j@aythya lectures]$ ./sumvalue
10
15
9.2
Parameters in Subroutines
Consider the following code, which contains the sub-function ‘frazzle’.
#include.<stdio.h>
/∗.Frazzle.uses.a.LOCAL.COPY.of.a,.doubles.it,.then
........prints.out.the.value..∗/
void.frazzle(int.a)
{
....a.=.a.∗.2;
....printf("In.frazzle:..a.=.%d\r\n",.a);
}
int.main(void)
{
....int.a=1;.................../∗.initialise.a.to.be.1.∗/
....printf("In.main:.....a.=.%d\r\n",.a);
....frazzle(a);
....a.=.a.+.2;................../∗.add.2.to.the.current.value.of.a.∗/
....printf("In.main:.....a.=.%d\r\n",.a);
....return.0;
}
What values will this code output to the screen?
Either: In main:
In frazzle:
In main:
a = 1
a = 2
a = 3
Or: In main:
In frazzle:
In main:
a = 1
a = 2
a = 4
61
COMO 102: Lecture 9, 2003
9.3
9.3.1
62
Pointers
Allowing Permanent Changes in Parameters
We can make permanent changes to parameters, rather than modifying a local copy,
by passing pointers to variables. Then the a local copy of the pointer is made, but
we can still access (and permanently change) the data being pointed to! This is
especially useful when we want a function to generate several values, as C only
allows us to return a single variable from a function. For example:
#include.<stdio.h>
/∗.swaps.two.variables.passed.as.POINTERS.to.integers.∗/
void.swap(int.∗aptr,.int.∗bptr)
{
....int.c;
....c.=.(∗aptr);................/∗.(∗aptr).‘dereferences’.the.pointer,.∗/
....(∗aptr).=.(∗bptr);........../∗.giving.access.to.the.memory.........∗/
....(∗bptr).=.c;................/∗.contents.(the.integer)!.............∗/
}
int.main()
{
....int.n1,.n2;
....n1.=.1;
....n2.=.2;
....printf("n1.=.%d,.n2.=.%d\n",.n1,.n2);
....swap(&n1,.&n2);............./∗.the.ampersand.creates.a.pointer.from
...................................a.variable..........................∗/
....printf("n1.=.%d,.n2.=.%d\n",.n1,.n2);
....return.0;.................../∗.normal.termination.∗/
}
[j@aythya lectures]$ gcc -o swap -Wall swap.c
[j@aythya lectures]$ ./swap
n1 = 1, n2 = 2
n1 = 2, n2 = 1
Why can’t we just go aptr=bptr in the swap routine instead of (*aptr)=(*bptr)?
COMO 102: Lecture 9, 2003
9.3.2
63
Pointer Values
#include.<stdio.h>
int.main()
{
....int.a;....................../∗.an.integer.∗/
....int.∗aptr;................../∗.a.pointer.to.an.integer.∗/
....a.=.27;
....aptr.=.&a;................../∗.aptr.now.points.to.a.∗/
....printf("a.=.%d,.(∗aptr)=%d,.aptr.=.%p.\n",.a,.(∗aptr),.aptr);
....return.0;
}
[j@aythya lectures]$ gcc -o pointy -Wall pointy.c
[j@aythya lectures]$ ./pointy
a = 27, (*aptr)=27, aptr = 0xbffffaa4.
Here we see that a has the value 27, the pointer aptr points to an integer with value
27, and that the memory address of this value being pointed to is 0xbffffaa4.
9.3.3
Pointers are Useful but *DANGEROUS*!
#include.<stdio.h>
int.main()
{
....int.a.=.27;
....int.∗aptr;
....aptr.=.&a;
....aptr.=.aptr.+.37;.........../∗.we.should.have.used..∗aptr.=.∗aptr.+.37.∗/
....printf("a=%d,.∗aptr=%d.\n",.a,.∗aptr);
....return.0;
}
[j@aythya lectures]$ gcc -o badbadbad -Wall badbadbad.c
[j@aythya lectures]$ ./badbadbad
a=27, *aptr=-1073742635.
COMO 102: Lecture 9, 2003
9.3.4
64
Making Pointers Safer
Pointers can be defined as constants, so that the memory address of the pointer can
not be changed. The data that the pointer points to is still able to be modified.
This reduces the likelihood of obscure programming errors considerably! Rewriting
our swap routine using this we get:
#include.<stdio.h>
/∗.Swaps.two.variables.passed.as.CONSTANT.pointers.to.integers..∗/
/∗.The.‘const’.keyword.means.the.pointers.can.not.be.changed,...∗/
/∗.however.the.contents.of.the.pointers.can.still.be.modified!..∗/
void.swap(int.∗const.aptr,.int.∗const.bptr)
{
....int.c;
....c.=.(∗aptr);................/∗.(∗aptr).‘dereferences’.the.pointer.∗/
....(∗aptr).=.(∗bptr);
....(∗bptr).=.c;
}
int.main()
{.............................../∗.main.routine.same.as.before..∗/
....int.n1,.n2;
....n1.=.1;
....n2.=.2;
....printf("n1.=.%d,.n2.=.%d\n",.n1,.n2);
....swap(&n1,.&n2);
....printf("n1.=.%d,.n2.=.%d\n",.n1,.n2);
....return.0;.................../∗.normal.termination.∗/
}
[j@aythya lectures]$ gcc -Wall -o goodswap goodswap.c
[j@aythya lectures]$ ./goodswap
n1 = 1, n2 = 2
n1 = 2, n2 = 1
Now if we accidentally use something like aptr=bptr instead of (*aptr)=(*bptr)
in the swap routine we get the following compilation error:
goodswap.c: In function ‘swap’:
goodswap.c:10: warning: assignment of read-only location
COMO 102: Lecture 9, 2003
9.3.5
65
Some Friendly Advice
In summary, when using pointers to change variables passed to functions:
• Always use -Wall when compiling your code, and always fix any sources of
warning messages!
• Always use const to prevent accidental and difficult to debug pointer problems.
9.4
Bug Finding and Indenting
The indent linux program makes your source code easier to read. The lclint program
helps find bugs in your code that the compiler may miss and also identifies a range
of poor programming practices. Consider, for example, the following ugly program:
#include.<stdio.h>
/∗.An.ugly.piece.of.code.that.we’ll.tidy.with.indent.∗/.
int.main().{.int.a;
a.=.7;.a=a∗a;.a=a∗a;
printf("a=%d\n",a);.}
9.4.1
lclint
[j@crusher lectures]$ lclint ugly.c
ugly.c: (in function main)
ugly.c:6:22: Path with no return in function declared to return int
There is a path through a function declared to return a value on which there
is no return statement. This means the execution may fall through without
returning a meaningful result to the caller. (Use -noret to inhibit warning)
Finished checking --- 1 code warning
9.4.2
indent
We use the “-kr” flag to turn on Kernighan and Ritchie coding style, which is a
little nicer than the default indenting, and “-o” to specify an output file.
[j@crusher lectures]$ indent -kr -o notugly.c ugly.c
COMO 102: Lecture 9, 2003
66
#include.<stdio.h>
/∗.An.ugly.piece.of.code.that.we’ll.tidy.with.indent.∗/
int.main()
{
....int.a;
....a.=.7;
....a.=.a.∗.a;
....a.=.a.∗.a;
....printf("a=%d\n",.a);
}
Note that indent is fairly safe and you generally don’t need to use the “-o” flag to
specify a different output file. However, the use of “-kr” is highly recommended.
Lecture 10 : Programming in C Part III
Chapter 10
10.1
Arrays
Programming in C Part III
As we have seen in Exercise 8, arrays are indexed starting from zero and elements
are accessed with square bracket notation. For example:
#include.<stdio.h>
void.arraydemo(double.anumber)
{
....double.myarray[10];........./∗.indexed.from.0.through.to.9.∗/
....int.i;
....for.(i.=.0;.i.<=.9;.i++)
........myarray[i].=.anumber.∗.(double).i;....../∗.convert.i.to.‘double’.∗/
....for.(i.=.0;.i.<=.9;.i++).{
........if.(i.>.0.&&.i.%.3.==.0)......../∗.If.i.is.3.or.6.or.9.or.....∗/
............printf("\n");
........printf("myarray[.%d.].=.%5.1f\t",.i,.myarray[i]);
....}
....printf("\n");
}
int.main(void)
{
....arraydemo(7.5);
....return.0;.................../∗.0.return.value.=.normal.termination..∗/
}
produces the output:
[j@aythya lectures]$ gcc -Wall ademo.c -o ademo
[j@aythya lectures]$ ./ademo
myarray[ 0 ] =
0.0
myarray[ 1 ] =
7.5
myarray[ 2 ] =
myarray[ 3 ] = 22.5
myarray[ 4 ] = 30.0
myarray[ 5 ] =
myarray[ 6 ] = 45.0
myarray[ 7 ] = 52.5
myarray[ 8 ] =
myarray[ 9 ] = 67.5
67
15.0
37.5
60.0
COMO 102: Lecture 10, 2003
68
The expression (double)i converts (‘casts’) the integer value of i to a double,
so that the multiplication is performed arithmetic. (Integer arithmetic discards
all fractional portions of the numbers.) To be safe, if you want a floating point
answer then you should convert all integers in a mixed expression to doubles using
(double) before the variable.
10.1.1
Passing Arrays to Subroutines
Consider the following main program:
#include.<stdio.h>............../∗.for.printf().∗/
#include.<stdlib.h>............./∗.for.rand()...∗/
#include."sorter.h"............./∗.our.sorting.header.file!.∗/
int.myrandom(int.a,.int.b)
{.............................../∗.find.a.random.number.between.a.and.b.∗/
....double.d.=.b.−.a.+.1.0,.t.=.RAND MAX.+.1.0;
....return.(a.+.(int).(d.∗.rand()./.t));
}
int.main(void)
{
....const.int.Max.=.6;
....int.i,.a[Max];
....printf("This.program.will.sort.%d.values:\n",.Max);
....for.(i.=.0;.i.<.Max;.i++)
........a[i].=.myrandom(1,.100);
....print array(a,.Max);
....bubble sort(a,.Max);
....printf("Sorted:\n");
....print array(a,.Max);
....return.0;
}
Rather than include all of the routines in one file, this program is broken into two
parts. The main code is in bubbles.c, and auxiliary sorting routines are declared in
sorter.h and defined in sorter.c. The main routine shown above uses a routine
called ‘bubble sort’ which is in the sorter files. Since we include sorter.h at the
start of the above code, the compiler knows about bubble sort.
COMO 102: Lecture 10, 2003
69
/∗.This.is.the.header.file.for.the.sorter.routines,
...which.are.defined.in.the.sorter.c.file...............∗/
void.swap(int.∗a,.int.∗b);
void.bubble sort(int.a[],.int.num);
void.print array(int.a[],.int.num);
In the header file above three functions are declared - swap, bubble sort and
print array. Note that the int a[] arguments of bubble sort and print array
allow passing of an array to the functions without specifying a constant size for
the array. We want the code to sort arrays of various sizes, so we pass a parameter
num, which gives the number of elements in the array a (a[0] through to a[num-1]).
#include.<stdio.h>............../∗.for.printf.(in.print array).∗/
#include."sorter.h"............./∗.include.our.previous.declarations,.
...................................from.the.sorter.h.header.file.−.this
...................................is.important.for.consistency!.∗/
void.swap(int.∗const.a,.int.∗const.b)
{.............................../∗.swap.two.numbers.(using.pointers).∗/
....int.t;
....t.=.∗a;
....∗a.=.∗b;
....∗b.=.t;
}
void.bubble sort(int.a[],.int.num)
{.............................../∗.A.bad.algorithm.for.sorting.an.array.∗/
....int.x,.y;
....for.(x.=.0;.x.<.num.−.1;.x++)
........for.(y.=.0;.y.<.num.−.1.−.x;.y++)
............if.(a[y].>.a[y.+.1])
................swap(&a[y],.&a[y.+.1]);
}
void.print array(int.a[],.int.num)
{.............................../∗.print.out.an.array.of.numbers.∗/
....int.i;
....printf("Array.=.{.%d",.a[0]);
....for.(i.=.1;.i.<.num;.i++)
........printf(",.%d",.a[i]);
....printf(".}\n");
}
COMO 102: Lecture 10, 2003
70
Compiling and running the code produces the following. Note that we need to
specify both bubble.c and sorter.c on the compilation line.
[j@crusher lectures]$ gcc -o bubble -Wall bubble.c sorter.c
[j@crusher lectures]$ bubble
This program will sort 6 values:
Array = { 85, 40, 79, 80, 92, 20 }
Sorted:
Array = { 20, 40, 79, 80, 85, 92 }
10.2
Writing output to a file: fprintf
Writing output to a file consists of three steps:
1. Opening the file (fopen).
2. Writing the data to the file (fprintf).
3. Closing the file (fclose).
For example, consider the following code:
#include.<stdio.h>
int.main(void)
{
....FILE.∗myfile;.............../∗.A.pointer.to.a.FILE.for.fopen.etc..∗/
....myfile.=.fopen("output.txt",."w");../∗.try.to.open.the.file.∗/
....fprintf(myfile,."Hello!.This.is.my.output.file!\n");
....fprintf(myfile,."3.+.4.=.%d\n",.3.+.4);
....fclose(myfile);
....return.0;
}
After running it we can view the output file either with nedit, or with the command
‘more’:
[j@bluebox lecture9]$ more output.txt
Hello! This is my output file!
3 + 4 = 7
The line ‘FILE * myfile’ declares the variable ‘myfile’ to be a pointer to a
FILE. We then assign myfile to be a newly opened file with filename ‘output.txt’
(the “w” indicates it be opened for writing, an “r” would open it for reading ). If
COMO 102: Lecture 10, 2003
71
for any reason the file was not able to be opened for writing myfile will be set to
‘NULL’, and we could test for this if we wished. fprintf works identically to printf
except that we specify the file to write to as a new first argument. When we are
finished printing to the file we close it with the ‘fclose’ command.
10.2.1
Exporting Data from C to MATLAB
#include.<stdio.h>
#include.<math.h>
/∗.This.must.be.compiled.with:
........gcc.−lm.−Wall.−o.tomatlab.tomatlab.cc.
...−lm.forces.the.inclusion.of.the.math.library.
........which.is.needed.for.the.sin(x)..................∗/
int.main(void)
{
....FILE.∗f;
....double.x;
....const.double.pi.=.3.141592654;
....f.=.fopen("xyvals.txt",."w");
....for.(x.=.0.0;.x.<=.2.∗.pi;.x.=.x.+.pi./.10.0)
........fprintf(f,."%e.%e\n",.x,.sin(x));
....fclose(f);
....return.0;
}
When compiled and run, the tomatlab code produces the following data:
[j@crusher lectures]$ more xyvals.txt
0.000000e+00 0.000000e+00
3.141593e-01 3.090170e-01
6.283185e-01 5.877853e-01
9.424778e-01 8.090170e-01
1.256637e+00 9.510565e-01
1.570796e+00 1.000000e+00
1.884956e+00 9.510565e-01
2.199115e+00 8.090170e-01
2.513274e+00 5.877853e-01
2.827433e+00 3.090170e-01
3.141593e+00 -4.102064e-10
(etc)
72
COMO 102: Lecture 10, 2003
And we can import and graph it in MATLAB with the following script m-file:
%JPLOT.Load.xyvals.txt.generated.by.the.C.program.and.graph.them!
load.-ascii.xyvals.txt
x=xyvals(:,1);.....%.the.first.column.is.the.x.values.
y=xyvals(:,2);.....%.the.second.column.is.the.y.values.
plot(x,y);
axis.tight;
1
0.8
0.6
0.4
0.2
0
−0.2
−0.4
−0.6
−0.8
−1
0
1
2
3
4
5
6
COMO 102: Lecture 10, 2003
10.3
73
Recursion
A function may call itself, and if it does it is said to be recursive. Consider the
following code, which shows two methods of calculating factorials.
#include.<stdio.h>
/∗.Calculates.n!.=.n∗(n−1)∗(n−2)∗.....∗3∗2∗1.∗/
int.factorial recursive(int.n)
{
....if.(n.==.0)
........return.1;
....else
........return.n.∗.factorial recursive(n.−.1);
}
/∗.Also.calculates.n!.=.n∗(n−1)∗(n−2)∗.....∗3∗2∗1.∗/
int.factorial loop(int.n)
{
....int.i;
....int.r;
....r.=.1;
....for.(i.=.2;.i.<=.n;.i++)
........r.=.r.∗.i;
....return.r;
}
int.main()
{
....int.n.=.12;
....printf("Recursive:.%d!.=.%d.\n",.n,.factorial recursive(n));
....printf("Loop:......%d!.=.%d.\n",.n,.factorial loop(n));
....return.0;
}
[j@crusher
[j@crusher
Recursive:
Loop:
lectures]$ gcc -o factorial -Wall factorial.c
lectures]$ factorial
12! = 479001600.
12! = 479001600.
Lecture 11 : Programming in C Part IV
Chapter
11 the fundamentals of C programming we will look at
Now that we have explored
writing code that is integrated into a larger system. This weeks work will focus on
the client-server “comotank” software, written specifically for this course. We will
write functions that control computer simulated hovertanks which obey a limited
set of physical laws. While the topic may seem a little frivolous, rest assured that
the programming skills and mathematics that you will learn this week are widely
applicable.
Programming in C Part IV
11.1
The Comotank Client-Server Framework
The comotank software runs as a ‘server’ program. The server launches multiple
‘client’ programs, where each client controls a simulated hovertank. The clients are
stand-alone C programs, which make use of a few simple functions (provided for
you) that communicate with the server.
11.1.1
The Rules
1. The hovertanks reside in a square arena, with coordinates in the range (−10, 000, −10, 000)
through to (10, 000, 10, 000).
2. The tanks are circular (as seen from above) and have a radius of 300 units.
3. They can be accelerated up to a maximum velocity of 120 units per second.
4. They can fire from a centrally mounted turret, which can rotate independently
of the tanks direction.
5. The shots travel at 175 units per second and are unaffected by the tanks
velocity when the shot is fired.
6. A shot directly hitting a tank will completely disable (kill) it.
7. The disabled tank acts as an obstacle for other tanks and shots. It can be
completely destroyed with a further three shots, removing it from the arena.
8. Tanks colliding with other tanks or walls are not damaged, but come to a
complete stop (instantly).
9. In a match points are awarded for disabling tanks (one per kill). A bonus of
n/3 points is awarded to the last surviving tank, where n is the initial number
of tanks in the arena.
10. Tanks can see down a narrow field of vision centred on their turret (within
radians either side of the turret).
74
π
20
COMO 102: Lecture 11, 2003
11.1.2
75
An Empty Client
When you first write your own hovertank controlling program you will start with a
copy of empty.c, which is shown below.
#include.<math.h>
#include.<stdlib.h>
const.double.Pi.=.3.1415926535897932385;
/∗.Use.these.functions.to.control.your.tank..∗/
void.accelerate(double.angle);../∗.in.radians......∗/
void.turn turret(double.delta angle);.../∗.in.radians......∗/
void.fire(void);................/∗.at.turret angle.∗/
/∗.These.variables.provide.information.about.your.tank...∗/
/∗.They.are.automatically.updated.every.time.you.use.one.∗/
/∗.of.the.above.three.functions..........................∗/
int.x,.y,.vx,.vy;.............../∗.position.and.velocity.∗/
double.turret angle;............/∗.in.radians.∗/
int.dist to closest enemy;....../∗.0.=.none,.>0.alive,.<0.dead.∗/
double.angle of closest enemy;../∗.in.radians.∗/
int.shots ready;
/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
/∗.The.main.routine.for.your.robot.hover.tank!.∗/
/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
void.robot(void)
{
}
During each game second the server accepts one accelerate, turn turret or fire
command from each of the clients. The clients (tank controlling programs) are
paused while the commands are executed. The server then updates the client variables (x,y,. . .,shots ready) to reflect the new state of each tank, and allows all of
the clients to continue execution. The clients can execute arbitrarily complex code
between the calls to accelerate, turn turret and fire, allowing for sophisticated
targeting and movement routines.
COMO 102: Lecture 11, 2003
11.1.3
76
The Controlling Functions in More Detail
Accelerate
This accelerates your tank at 60 units/s2 for one quarter of a second in the direction
angle, which is an absolute angle in radians (measured anti-clockwise from the xaxis).
Turn Turret
This turns the gun turret by a specified CHANGE in angle, which must lie between
π
π
and 20
. Angles outside this range will be ignored. To skip a turn, letting the
− 20
tank glide at its current velocity, you can use turn turret(0.0).
Fire
If you have any shells ready to fire (check with the shots ready variable) then this
fires one shell in the current turret direction. Otherwise the command is ignored,
wasting a second of game time for your tank.
COMO 102: Lecture 11, 2003
11.1.4
77
A Simple Tank
#include.<math.h>
#include.<stdlib.h>
const.double.Pi.=.3.1415926535897932385;
void.accelerate(double.angle);../∗.in.radians......∗/
void.turn turret(double.delta angle);.../∗.in.radians......∗/
void.fire(void);................/∗.at.turret angle.∗/
/∗.These.variables.provide.information.about.your.tank...∗/
int.x,.y,.vx,.vy;.............../∗.position.and.velocity.∗/
double.turret angle;............/∗.in.radians.∗/
int.dist to closest enemy;....../∗.0.=.none,.>0.alive,.<0.dead.∗/
double.angle of closest enemy;../∗.in.radians.∗/
int.shots ready;
/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
/∗.sucky.c.−.the.controlling.program.for.the.sucky.tank..∗/
/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
void.robot(void)
{
....if.(dist to closest enemy.>.0).{..../∗.Can.we.see.something?.∗/
........if.(shots ready.>.0)
............fire();............./∗.shoot.∗/
......../∗.Aim.−.this.wont.always.work.for.two.reasons..∗/
........turn turret(angle of closest enemy.−.turret angle);
....}.else.{
......../∗.look.around!.∗/
........turn turret(Pi./.20.0);
....}
}
11.1.5
Compiling and Testing
This code is compiled with the following command. The generic.c file contains
the definitions for accelerate, turn turret, and fire.
[j@crusher run]$ gcc -Wall -o sucky sucky.c generic.c
COMO 102: Lecture 11, 2003
78
The comotank program can then be run, for example with three of the ‘sucky’
tanks:
[j@crusher run]$ comotank sucky sucky sucky
Gamestate initialised: 3 tanks (50 max).
Tank
sucky (#01) KILLED by
sucky (#02)!
Tank
sucky (#03) KILLED by
sucky (dead)!
Game time: 59 secs (236 cycles), [0 real seconds].
(Tank #2 wins)
WINNER: sucky [1 kills]!
11.1.6
Utilities Available
We can review the battle graphically with the tankview program, or run a set of
matches with bigmatch. How does our tank (sucky) stack up against the notorious
wuffles.mk4? Lets use bigmatch to check with 100 one-on-one battles:
[j@crusher run]$ bigmatch 100 1 sucky wuffles.mk4
Battle of 100 matches, 1 of each tank type.
+-----------------+---------+-----------+-----------+
|
Tank
|
Wins |
Kills |
Points |
+-----------------+---------+-----------+-----------+
|
wuffles.mk4
|
91 |
91 |
151 |
|
sucky
|
9 |
9 |
15 |
+-----------------+---------+-----------+-----------+
And we see that wuffles.mk4 is far superior. You will have several designs to compare
your tanks against, ranging from the poorly performing findshoot and tatie to
the sophisticated wuffles models. Large numbers of matches can be run, as shown
below:
COMO 102: Lecture 11, 2003
11.1.7
79
Tankview
Tankview reviews the most recently stored battle graphically. An example screenshot is shown below.