Faculty of Engineering Technology
Programming in Engineering 2018
Thomas Weinhart, Anthony Thornton, Wouter den Otter, Deepak Tunuguntla, Kit Windows-Yule, Katja Bertoldi, Holger Steeb and Stefan Luding
edition: 2018
Contents
Contents
i
Preface
ix
Acknowledgement
ix
History
x
Preliminaries
A
xii
MATLAB
1
1 Getting started with Matlab
2
1.1
Input via the command-line . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.2
help-facilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.3
Interrupting a command or program . . . . . . . . . . . . . . . . . . . . . . . .
6
1.4
Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.5
Workspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.6
Saving and loading data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.7
Exercises
9
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Basic syntax and variables 2.1
10
Matlab as a calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
2.1.1
11
An introduction to floating-point numbers . . . . . . . . . . . . . . . . .
–i–
Contents
ii 2.1.2
2.2
Assignments and variables . . . . . . . . . . . . . . . . . . . . . . . . . .
Exercises
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Mathematics with vectors and matrices 3.1
3.2
Vectors
12 15 16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.1.1
Row vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.1.2
Colon notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
3.1.3
Extracting and appending parts of a vector . . . . . . . . . . . . . . . .
18
3.1.4
Column vectors and transposing . . . . . . . . . . . . . . . . . . . . . .
19
3.1.5
Products, divisions and powers of vectors . . . . . . . . . . . . . . . . .
20
Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
3.2.1
Special matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
3.2.2
Building matrices and extracting parts of matrices . . . . . . . . . . . .
24
3.2.3
Matrix operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
3.3
Exercises
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.4
Appendix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
4 Scripts
35
4.1
Script m-files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
4.2
Creating and running a script . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
4.3
Exercises
36
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 Control flow 5.1
37
Logical and relational operators . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
5.1.1
Logical indexing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
5.1.2
The find command . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
Conditional code execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
5.2.1
Using if ...
end . . . . . . . . . . . . . . .
42
5.2.2
Using switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
5.3
Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
5.4
Comments on logical and relational expressions . . . . . . . . . . . . . . . . . .
47
5.2
elseif ...
else ...
Contents
iii
6 Functions
50
6.1
Function m-file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
6.2
Local and global variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
6.3
Subfunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
6.4
Nested functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
6.5
Special function variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
6.6
Indirect function evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
6.7
Scripts versus functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
6.8
Exercises
58
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 Cell arrays and structures
60
7.1
Cell arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
7.2
Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
7.3
Object handles and the internal set and get functions
. . . . . . . . . . . . . .
63
Parents and children . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
7.3.1
8 File input/output operations 8.1
8.2
68
Formatted files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
8.1.1
Writing formatted files . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
8.1.2
Reading formatted files . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
Excel files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
9 Writing and debugging Matlab programs
72
9.1
Structural programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
9.2
Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
9.3
Recommended programming style . . . . . . . . . . . . . . . . . . . . . . . . . .
76
9.4
Commenting and publishing in MATLAB . . . . . . . . . . . . . . . . . . . . .
77
9.4.1
77
Publishing Matlab code . . . . . . . . . . . . . . . . . . . . . . . . . .
10 Matlab and execution speed 10.1 Vectorizing your code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78 78
Contents
iv
10.2 Pre-allocation of arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Visualisation
79 80
11.1 2D plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
11.2 Several functions in one figure . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
11.3 Adding text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
11.4 Changing the axes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
11.5 Fine-tuning plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
11.6 Saving graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
11.7 Exporting graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
11.8 Plotting surfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
11.9 3D line plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
87
11.10Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
87
11.11Exercises
88
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12 Numerical analysis 12.1 Differentiation
90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
90
12.2 Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
92
12.2.1 Matlab commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
12.3 Solving differential equations - the ODE toolbox . . . . . . . . . . . . . . . . .
93
12.3.1 First order ODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
12.3.2 Systems of ODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
12.4 Exercises
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13 Symbolic computation
96 98
13.1 Symbolic objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
13.2 Solving symbolic expressions
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
13.3 Matrix and and vector operations . . . . . . . . . . . . . . . . . . . . . . . . . .
100
13.4 Differentiation and integration
. . . . . . . . . . . . . . . . . . . . . . . . . . .
101
13.5 Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
102
13.6 Solving ordinary differential equations . . . . . . . . . . . . . . . . . . . . . . .
103
Contents
B
v
13.7 Summations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
104
13.8 Symbolic substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
105
C++
14 Introduction to C++
106 107
14.1 Objective of the course . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
107
14.2 Installation of a C++ compiler/IDE . . . . . . . . . . . . . . . . . . . . . . . .
107
14.3 A short history of C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
108
14.4 Why use C++? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
109
15 Programming-style
110
15.1 Comments (see also §16.1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
110
15.2 Clear style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
111
16 The basics
112
16.1 Language Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
112
16.2 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
113
16.3 data types, Variables, Constants . . . . . . . . . . . . . . . . . . . . . . . . . .
114
16.3.1 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
114
16.3.2 Basic data types and their declaration . . . . . . . . . . . . . . . . . . .
115
16.3.3 Type conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
118
16.3.4 Variable-attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
118
16.3.5 string type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
119
16.3.6 String stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
119
16.3.7 Life-time and position in memory . . . . . . . . . . . . . . . . . . . . . .
120
16.3.8 Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
121
16.4 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
123
16.4.1 Arithmetic operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
123
16.4.2 Assignment and increment operators . . . . . . . . . . . . . . . . . . . .
124
Contents
vi 16.4.3 Comparison and logical operators . . . . . . . . . . . . . . . . . . . . . .
124
16.4.4 Further operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
125
16.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
126
17 Decision structures
128
17.1 The if-command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
128
17.2 The ternary ?: operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
129
17.3 switch-command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
130
18 Loop control structures
131
18.1 (do) while-loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
131
18.2 for-loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
132
18.3 break and continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
132
19 Functions and Operators
134
19.1 Transfer of arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
136
19.1.1 Example of passing by reference . . . . . . . . . . . . . . . . . . . . . .
136
19.2 Functions without arguments or return value – void . . . . . . . . . . . . . . .
137
19.3 Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
138
19.4 inline functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
19.5 Overloading of functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
19.6 Templated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
20 Pointers, pointer-field duality, and references
141
20.1 Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
141
20.1.1 Pointer to void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
144
20.2 pointer-field duality
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
145
20.3 Transfer of field-variables to functions . . . . . . . . . . . . . . . . . . . . . . .
145
20.4 Dynamical Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . .
148
21 Object Oriented Programming I: Containers in the Standard Template Library 149 21.1 C++ standard classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
149
Contents
vii
21.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
150
21.3 Vectors
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
153
21.4 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
154
21.5 Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
156
21.6 Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
158
21.6.1 Iterator operators
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
158
21.6.2 Iterator member functions . . . . . . . . . . . . . . . . . . . . . . . . . .
158
21.6.3 Declaring and using iterators . . . . . . . . . . . . . . . . . . . . . . . .
159
21.7 Range-Based for loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
162
22 Object Oriented Programming II: Creating New Classes
166
22.1 A simple OOP problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
166
22.2 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
168
22.3 Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
168
22.4 C++ standard classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
172
22.5 STL vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
173
23 I/O (Input and Output)
175
23.1 Elementary functions of iostreams . . . . . . . . . . . . . . . . . . . . . . . . .
175
23.2 Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
176
23.3 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
177
24 Organisation implementation and header-files 24.1 Compiling and linking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Functional Programming
180 182 183
25.1 Function Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
183
25.1.1 std::functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
186
25.2 Lambda Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
189
25.2.1 An Introduction to Lambda Functions . . . . . . . . . . . . . . . . . . .
189
25.2.2 Lambdas in Action – Making a DIY CTRL+F . . . . . . . . . . . . . .
190
Contents
viii 25.2.3 Summary of Capture Specifiers . . . . . . . . . . . . . . . . . . . . . . .
26 Literature and longer exercises
196 200
26.1 Further reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
200
26.2 Longer exercises C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
201
Contents
ix
Preface This manuscript contains short introductions to the interpreter language Matlab and the object-oriented compiler language C++, including many small and large exercises. The manuscript consists of two parts: The first part covers Matlab, the second part is an introduction to C++. Both parts are self-contained, but cross-references and similarities are highlighted. Therefore, students who are interested in self-study can begin either with the Matlab or the C++ part. Within both parts you will find numerous small examples and exercises. These can be used for self-evaluation. At the end of every chapter you will find various larger exercises similar to the exercises of the final assignment.
Acknowledgement This work includes material from “Programming in Engineering” by Stefan Luding, Holger Steeb and Katja Bertoldi (all from the University of Twente) and “Introduction to Matlab” by El˙zbieta P¸ekalska (Delft University of Technology), with contributions from Hans Zwart, Anthony Thornton, Thomas Weinhart, Deepak Tunuguntla, Kit Windows-Yule and Wouter den Otter (all from the University of Twente). The respective authors have given us permission to re-use their work.
Contents
x
History Version 1.0
The manuscript was compiled for the 10-day summer course Programming in Engineering, July - 18 July 2008.
Version 1.1
Updated for self-study purposes, 3 September 2008
Version 1.2
Compiled for the 10-day summer course Programming in Engineering, 6 July-17 July 2009. This version also used for self-study program beginning 2 September 2009.
Version 1.3
Extended and updated by Stefan Luding and Anthony Thornton, for the 10-day summer course Programming in Engineering 5 July - 18 July 2010. Short exercise added to the C++ part. This version also will be used for self-study program beginning 30 August 2010.
Version 1.4
More information on OOP added and other general improvements to both C++ and MATLAB part. Designed for use in the Summer school 2011 and for the self study for 2011/12 academic year (Anthony Thornton).
Version 1.5
Even more information on OOP to C++ , details of handles added to MATLAB part, and other general improvements to both C++ and MATLAB part. Designed for use in the Summer school 2012 and for the self study for 2012/13 academic year (by Thomas Weinhart & Anthony Thornton).
Version 1.6
Script updated to reflect change of order. Now Matlab is taught before C++ (by Anthony Thornton).
Version 1.7
C++ part updated: templates added, intro to STL added, various other sections reworded and the whole documented was reordered to reflect the way it was taught for summer 2013. This was used for the September 2013 and 2014 version of the course (by Anthony Thornton).
Version 1.8
This will be used for the July 2015 version of the course by Deepak Tunuguntla, Thomas Weinhart and Kit Windows-Yule. Matlab section has a general clean up and the long exercises where removed (Deepak Tunuguntla).
Version 1.9
General update of Matlab section, including expanding sections on complex numbers, find command, commenting, set and get functions, use of handles (in particular ode solvers). Additionally new sections where added on nested functions, code publishing, subs command and vectorising. (Anthony Thornton). For C++, created a C++11 standard function section; this includes new information on iterators and range-based for loops. Added new chapter on functional programming, dealing with function pointers, std::functions and lambda functions (Kit Windows-Yule). This version was used for the summer course 2016.
Version 1.10
Thorough revision of the Matlab section to make it more consistent and selfcontained, and up-to-date with the ever changing commands in Matlab (Wouter den Otter). Various small updates implemented for the summer course starting July 10, 2017 (Thomas Weinhart).
Version 1.11
Assorted minor revisions for the summer course starting July 9, 2018 (Wouter den Otter and Anthony Thornton).
Contents
xi
Contents
xii
Preliminaries Below you find a short list of basic definitions concerning computers and programming. Please get acquainted with these keywords as they introduce key concepts needed in the coming sections: • A bit (short for binary digit) is the smallest unit of information on a computer. A single bit can hold only the value 0 (zero) or 1 (one). More meaningful information is obtained by combining consecutive bits into larger units, such as bytes. • A byte is a combination of 8 bits, capable of holding 28 = 256 distinct values. Floating point numbers are stored in 8 bytes, strings use 1 byte per character. Memory is measured in terms of kilobytes (1024 bytes), megabytes (1024 kB), and gigabytes (1024 MB). • Binary system - a number system that has two digits only, 0 and 1. Computers are based on this system because of their electrical nature (charged versus uncharged, current versus no current). Similar to our decimal system, where each digit position represents a specific power of 10, in the binary system each digit position represents a specific power of 2, with the power increasing from right to left. Here is an example of a binary number (denoted by the subscript 2) and its decimal representation (subscript 10): 101102 = 1 · 24 + 0 · 23 + 1 · 22 + 1 · 21 + 0 · 20 = 2210 = 2 · 101 + 2 · 100 . • Data is information represented using symbols, e.g. numbers, words, signals or images. • A command is an instruction to do a specific task. • An algorithm is a sequence of instructions for the solution of a specific task in a finite number of steps. • A program is the implementation of an algorithm suitable for execution by a computer. • A variable is a ‘container’ that can hold a value. For example, the expression x = 2*y relates the variables x and y. Variables can represent numeric values like 25.5, characters like ‘c’ or character strings like ‘Matlab’. Variables make programs more flexible. When a program is executed, the variables are replaced with real data; for y = 4, the above expression becomes x = 8. That is how a program can process different sets of data. Every variable has a name (called the variable name) and a data type. A variable’s data type indicates the sort of data that the variable can represent (see below). • A constant is a container holding a value that never changes. It can be a numeric value, a character or a string. • A data type is a classification of the type of information. The basic data types are: • integer: a whole number, i.e. a number that has no fractional part, e.g. 3. • floating-point: a number with a decimal point, e.g. 3.5 or 1.2e–16 (= 1.2 ∗ 10−16 ). • character: readable text character, e.g. ‘p’. • A bug is an error in a program. Depending on the type of bug, is may cause the program to stop running, not to run at all or to provide wrong results. Some bugs can be very subtle and hard to find. The process of finding and removing bugs is called debugging. • A file is a collection of data or information stored on an internal or external data storage device (hard disk, USB stick, backup-tape). There are many different types of files: data files, program files, text files etc. • An ASCII file is a readable and editable plain text file, using the American Standard Code for Information Interchange (ASCII). • A binary file is a file stored in a computer-readable format, not meant to be humanreadable. All executable programs and most numeric data are stored in binary files. Matlab creates binary files with the extensions ‘*.mat’ and ‘*.fig’.
Part A MATLAB
–1–
Chapter 1 Getting started with Matlab
Matlab is a tool for performing or executing mathematical (technical) calculations. Besides its usage as a scientific calculator, it also allows you to plot or visualise data in several possible ways. In addition, it allows for complex matrix manipulations, polynomial operations, differentiation and integration of functions and many more useful features essential for our problem analysis. Like in a programmable calculator, you can create, execute and save a sequence of commands in order to make your computational process automatic and repeatable. It can be used to store or retrieve data. In summary, Matlab can also be treated as a user-friendly programming language, which gives the possibility to handle mathematical calculations in an easy way. As a computing/programming environment, Matlab is especially designed to work with data sets as a whole such as vectors, matrices and images. Tools such as, PRTOOLS (http://prtools.org), a toolbox for Pattern Recognition, and DIPIMAGE (http://www.ph.tn.tudelft.nl/DIPlib/dipimage_1.html), a toolbox for Image Processing, have been developed under Matlab. Under Windows, you can start Matlab by double clicking on the Matlab icon that should be on the desktop of your computer. On a unix system, type matlab at the command line. Running Matlab creates one or more windows on your screen. The most important is the Command Window , which is the place where you interact with Matlab, i.e. it is used to enter commands and display text results. The string >> is the Matlab prompt (or EDU>> for the Student Edition). When the Command Window is active, a cursor appears after the prompt, indicating that Matlab is waiting for your command. Matlab responds by printing text in the Command Window or by creating a Figure Window for graphics. To exit Matlab use the command exit or quit. Control-C is a local abort which kills the current execution of a command.
1.1
Input via the command-line
Matlab is an interactive system: commands followed by Enter are executed immediately. The
–2–
1.1. Input via the command-line
3
results are, if desired, displayed on screen. However, execution of a command will only be possible if the command is typed according to the rules. Table 1.1 shows a list of commands used to solve indicated mathematical equations. Below you find basic information to help you starting with Matlab: • Commands in Matlab are executed by pressing Enter or Return. The output will be displayed on screen immediately. Try the following (hit Enter after the end of line): >> 3 + 7.5 >> 18/4 >> 3 * 7
Note that spaces are not important in Matlab. • The result of the last performed computation is ascribed to the variable ans, which is an example of a Matlab built-in variable. It can be used in the subsequent command. For instance: >> 14/4 ans = 3.5000 >> ansˆ(−6) ans = 5.4399e−04
5.4399e-04 is a computer notation of 5.4399 ∗ 10−4 (see ). Note that ans is always overwritten by the last command that has no assignment. • You can also define your own variables. To assign values to the variables a and b: >> a = 14/4 a = 3.5000 >> b = aˆ(−6) b = 5.4399e−04
Read Preliminaries to better understand the concept of variables. You will learn more on Matlab variables in section 2.1.2. Not that the equals sign ‘=’ is best read as ‘becomes.’ • When a command is followed by a semicolon ’;’, the output is suppressed. Check the difference between the following expressions: >> x = 3 + 7.5 >> y = 3 + 7.5;
• It is possible combine multiple commands in a single line, by separating the commands by commas (to display the output) or by semicolons (to suppress the output display), e.g.: >> sin(pi/4), cos(pi); sin(0) ans = 0.7071 ans = 0
Note that the value of cos(pi) is not printed. • By default, Matlab displays floating point numbers using 4 decimals. and format long increases this number to 15, format short reduces it to 4 again. For instance:
1.1. Input via the command-line
4
> 312/56 ans = 5.5714 >> format long >> 312/56 ans = 5.57142857142857
• The output may contain some empty lines; this can be suppressed by the command format compact. In contrast, the command format loose will insert extra empty lines. • To enter a statement that is too long to be typed in one line, use three periods ’...’ followed by Enter or Return. For instance: >> sin(1) + sin(2) − sin(3) + sin(4) − sin(5) + sin(6) − ... sin(8) + sin(9) − sin(10) + sin(11) − sin(12) ans = 1.0357
• Matlab is case sensitive, hence a and A are two distinct variables. • All text after a percent sign % until the end of a line is treated as a comment. Enter e.g. the following: >> sin(3.14159)
• • • •
% this is an approximation of sin(pi)
You will notice that some examples in this text are followed by comments. They are meant for you and you should skip them while typing. Previous commands can be retrieved with the ↑ -key. The command can also be changed; the ← and → -keys may be used to move around in a line and edit it. To recall the most recent command line starting with e.g. c, type c at the prompt followed by the ↑ -key. Similarly, cos followed by the ↑ -key will retrieve the last command-line starting with cos. Use the tab key for automated completion of commands and variable names; try for instance shou
and sho and see what happens. The command window is cleared by typing clc.
Since Matlab executes the command immediately, it might be useful to have an idea of the expected outcome. You might be surprised how long it takes to print out a 1000 × 1000 matrix!
1.2. help-facilities
5 Mathematical notation a+b a−b ab a b
xb √ x |x| π 4 ·√103 i( −1) 3 − 4i e, ex ln x, log x sin x, arctan x, ...
Matlab command a + b a - b a * b a / b or b \ a x^b sqrt(x) or x^0.5 abs(x) pi 4e3 or 4*10^3 i or j or 1i or 1j 3-4*i or 3-4j exp(1), exp(x) log(x), log10(x) sin(x), atan(x),...
Table 1.1: Mathematical notation and the corresponding commands in Matlab (where a, b, x and y are numbers).
1.2
help-facilities
There are several ways for getting help with MATLAB. A good way to start is to press the ‘Help’ button to type: >> doc
The doc command opens an HTML document, which contains the Matlab reference book. This is quite a large document! Useful sections for beginners include Getting Started and Matlab Functions. You might want to browse them before beginning your first session. Its helpful to keep this browser window open while you are working with Matlab, so that you can refer to it easily. There are other ways of getting help with Matlab that do not make you search through the whole reference book. If you already know the name of a Matlab function, for example, quit, and you want to learn about its use, enter: >> help quit
You will see a description of the command quit. You can also open the help in a browser window using doc quit. During your first experiences with Matlab you can from time to time take a: >> demo
session which will show you various features of Matlab. Another very useful feature is the lookfor command. It looks for all the commands related to a given topic (which can make it very slow). Try:
1.3. Interrupting a command or program
6
>> lookfor 'help'
It will list all of the commands we just discussed. Besides the inherent help of Matlab, you will find various online courses and references in the internet and, last but not least, textbooks. Here, we just mention a view: Online sources • Matlab home page (from manufacturers) http://www.mathworks.com • Matlab online course (TU Eindhoven) http://www.imc.tue.nl • Matlab online Reference Documentation http://www.math.ufl.edu/help/matlab/ReferenceTOC.html Books and others references • Matlab An Introduction with Applications, Amos Gilat, 2008. • Matlab Programming for Engineers, Stephen Chapman, 2007. • Essential Matlab for Engineers and Scientists, Brian Hahn and Dan Valentine, 2007.
1.3
Interrupting a command or program
Sometimes you might spot an error in your command or program. Due to this error it can happen that the command or program does not stop. Pressing Ctrl-C (or Ctrl-Break on PC) forces Matlab to stop the process. Sometimes, however, you may need to press a few times. After this the Matlab prompt (>>) re-appears. This may take a while, though.
1.4
Path
The Matlab ‘path’ is a list of directories that tells Matlab where to find relevant m-files. Whenever you enter a command, Matlab searches the directories in the path until it comes across an m-file with the same name (plus the .m extension) and then executes that procedure. Basically, the path defines the universe in which Matlab is working at a given time. A few technical notes: when you enter something in the command line, Matlab actually begins by looking for a variable of the given name, then for an m-file in the current directory, and only then does it search in its path. Hence, if the current directory contains an m-file whose name matches the requested command, Matlab executes that m-file and never enters the path. The type of m-file is irrelevant to the search procedure: Matlab executes the first match it finds,
1.5. Workspace
7
regardless of whether it contains a script, function or an object method. Finally, you should never use variables and functions (described in the following chapters) of the same name. To display or modify the path, use the path, addpath and rmpath functions. One may also click on the Set Path button in the ‘environment’ segment under the ‘home’ tab. Why does it matter? Proper path management is essential to ensure smooth running code. In order to invoke any code, its m-file must be in one of the directories contained in the path. Calling a procedure that is stored outside of the path will result in errors. A bit more subtly, the order in which directories appear in the path can affect how your code functions. If you ever create two functions with the same definitions (called overloading), then Matlab will call whichever one it encounters first. Users often overload standard toolbox functions with (slight) modifications of their own. Overloading functions requires that you be very careful in defining your Matlab path. The current working directory is resolved by typing pwd, while cd is used to change the working directory. The contents of the working directory is listed by dir or ls. Exercise 1.1. Type path to check which directories are placed on your path. Add you personal directory to the path (assuming that you created your personal directory for working with Matlab).
1.5
Workspace
All variables you create in the Command Windows are stored in Matlab’s workspace. All variables contained in your workspace can be listed with the command who. The command whos provides additional information on the number of allocated bytes and the class of all variables. For example, assuming that you performed all commands from section 1.1, after typing who you should get the following information: >> who Your variables are: a ans b
x
The command clear deletes the variable from the Matlab workspace, clear or clear all removes all variables. This is useful when starting a new exercise. For example: >> clear a x >> who Your variables are: ans b
Note that you cannot use comma after a variable, i.e. clear a, x, as it will be interpreted in Matlab as clear a and print x on the screen. See what is the result of: >> clear all >> a = 1; b = 2; c = 3; >> clear a, b, c
1.6. Saving and loading data
8
>> clear b c
Matlab also offers a separate window to display the contents of its workspace (in the ’home’ tab, click ’layout’ and select ’workspace’). Try what happens when you double-click on a variable name.
1.6
Saving and loading data
The easiest way to save or load Matlab variables is by clicking the Save Workspace or the Open button, respectively. Also Matlab commands exist which save data to files and which load data from files. The command save allows for saving your workspace variables either in a binary file or an ASCII file (check the ‘Preliminaries’ for the differences). Binary files automatically get the ‘.mat’ extension. There is no automatic extension to ASCII files, so it is recommended to add the extension ‘.txt’ or ‘.dat’ by hand. Exercise 1.2. Learn how to use the save command by exercising: >> >> >> >> >> >> >> >> >>
clear all s1 = sin(pi/4); c1 = cos(pi/4); c2 = cos(pi/2); str = 'hello world'; % this is a string save % saves all variables in binary format to % matlab.mat save data % saves all variables in binary format to data.mat save numdata s1 c1 % saves numeric variables s1 and c1 to numdata.mat save strdata str % saves a string variable str to strdata.mat save allcos.dat c* −ascii % saves c1,c2 in 8−digit ascii format to % allcos.dat
The load command allows for loading variables into the workspace. It uses the same syntax as save. Exercise 1.3. Assuming that you have done the previous exercise, try to load variables from the created files. Before each load command, clear the workspace and after loading check which variables are present in the workspace (use who). >> load >> load data s1 c1 >> load strdata
% % % %
loads all variables from the file matlab.mat loads only specified variables from the file data.mat loads all variables from the file strdata.mat
It is also possible to read ASCII files that contain rows of space separated values. Such a file may contain comments that begin with a percent character. The resulting data is placed into a
1.7. Exercises
9
variable with the same name as the ASCII file (without the extension). Check, for example: >> load allcos.dat >> who
% loads data from allcos.dat into variable allcos % lists variables present in the workspace now
1.7
Exercises
Exercise 1.4. • Is the inverse cosine function, known as cos−1 or arccos, one of Matlab’s elementary functions? • Does Matlab have a mathematical function to calculate the greatest common divisor? • Look for information on how to compute logarithms; what is the syntax for ln(a), log10 (a), log2 (a)? Use help or lookfor to find out.
Chapter 2 Basic syntax and variables
2.1
Matlab as a calculator
There are three kinds of numbers used in Matlab: integers, real numbers and complex numbers. In addition, Matlab has representations of the non-numbers: Inf, for positive infinity, generated e.g. by 1/0, and NaN, Not-a-Number, obtained as a result of the mathematically undefined operations such as 0/0 or ∞ - ∞. You have already got some experience with Matlab and you know that it can be used as a calculator. To do that you can, for example, simply type: >> (23*17)/7
The result will be: ans = 55.8571
Matlab has six basic arithmetic operations, such as: +, -, *, / or \ (right and left divisions) and ^ (power). Note that the two division operators are different (especially for matrices, as we will see later): >> 19/3 ans = 6.3333 >> 19\3, 3/19 ans = 0.1579 ans = 0.1579
% mathematically: 19/3
% mathematically: 3/19
Basic built-in functions, trigonometric, exponential, etc, are available for a user. Try help
– 10 –
2.1. Matlab as a calculator
11
elfun to get the list of elementary functions. Exercise 2.1. Evaluate the following expressions by hand and use Matlab to check the answers. Note the difference between the left and right divisors. Use help to learn more on commands rounding numbers, such as: round, floor, ceil, etc. • 2/2 ∗ 3
• 3^2/4
• 8 ∗ (5\4)
• 2 + round (6/9 + 3 ∗ 2)/2
• 8 ∗ 5\4
• 7 − 5 ∗ 4\9
• 6 − 2/5 + 7^2 − 1
• 10/2\5 − 3 + 2 ∗ 4
• 3^2^3
• 2 + floor (6/9 + 3 ∗ 2)/2 • 2 + ceil (6/9 + 3 ∗ 2)/2
• x = pi/3, x = x − 1, x = x + 5, x = abs(x)/x
intermezzo
2.1.1
An introduction to floating-point numbers
In a computer, numbers can be represented only in a discrete form. This means that numbers are stored within a limited range and with a finite precision. Integers can be represented exactly with the base of 2 (read Preliminaries on bits and the binary system). The typical size of an integer is 32 bits, in which case the largest storable positive integer 232 = 4294967296. If negative integers are permitted, then 32 bits allow for storage of integers between intmax(’int32’) = 2147483647 and intmin(’int32’) = -2147483648. Within this range, operations defined on the set of integers can be performed exactly. Be prepared for unexpected behaviour when using integers outside their range of validity (try: i = intmax(’int8’), i = i + 1 ). However, this is not valid for other real numbers. In practice, computers are integer machines and are capable of representing real numbers only by using complicated codes. The most popular code is the floating point standard. The term floating point is derived from the fact that there is no fixed number of digits before and after the decimal point, meaning that the decimal point can float. Note that most floating-point numbers that a computer can represent are just approximations. Therefore, care should be taken that these approximations lead to reasonable results. If a programmer is not careful, small discrepancies in the approximations can cause meaningless results. Note the difference between e.g. the integer arithmetic and floating-point arithmetic: Integer arithmetic: 2 + 4 = 6 3 * 4 = 12 25/11 = 2
Floating-point arithmetic 18/7 = 2.5714 2.5714 * 7 = 17.9998 10000/3 = 3.3333e+03
Floating point numbers are often classified as single precision (32 bits) or double precision (64 bits). In binary form, floats are of the form ±1.xxxx ∗ 2±yy where every x in the fraction and every y in the exponent is either 0 or 1. The fraction and exponent (and their signs) are stored
2.1. Matlab as a calculator
12
together in 32 (or 64) bits. In practice, switching from 32 to 64 bits increases not only the size of the fraction – to store numbers more accurately – but also increases the size of the exponent – to widen the range of stored numbers to both larger and smaller (i.e. closer to zero) values. The relative accuracy might be defined as the smallest positive number ǫ that, when added to 1, creates a numerical result larger than 1, i.e. 1 + ǫ > 1. In floating-point arithmetic, for positive values δ smaller than ǫ, the result of 1 + δ equals 1 (whereas in exact arithmetic, of course, the result is always larger than 1). In Matlab, the value of ǫ is stored in the built-in variable eps ≈ 2.2204e − 16. This value implies that the relative accuracy of individual arithmetic operations is about 15 digits. Matlab relies on your computer’s floating point arithmetic. You could have noticed that in the last exercise, where the value of sin(pi) was almost zero but not completely zero. This stems from the value of π being represented by pi with a finite precision, as well as from the function sin being evaluated with a finite precision. The fundamental type in Matlab is double, which stands for a representation with a double precision, i.e. using 64 bits. The single precision obtained by using the single type offers 32 bits. Since most numeric operations require high accuracy, the double type is used by default. Even when the user is inputting integer values in Matlab, e.g. k = 4, the data is still stored in the double format (unless the user explicitly requests integers, e.g. k = int32(4)). end intermezzo
2.1.2
Assignments and variables
Assigning variables in Matlab is easy. Consider the code below >> i=4; >> x=2.5;
It assigns 4 to the variable i and 2.5 to variable x.
Complex numbers in Matlab Working with complex numbers is easily done with Matlab. There are two ways to declare a complex number >> z1 = complex(3,4) >> z2 = 3+4i;
Note that i and j are often used as a loop counters and thereby loose their special values. Consider the code >> i >> z1 = 3+4*i
2.1. Matlab as a calculator
13
>> i = 4 >> z2 = 3+4*i >> z3 = 3+4i
√ Note that only without the multiplication sign in front do i and j always equal −1. Be warned that redefining i and/or j is an easy mistake to make... The problem with redefinition of internal variables and internal functions can occur in many ways. Consider the code. >> quit = 1; >> quit
More examples of this type will be discussed below. Exercise 2.2. Choose two complex numbers, for example -3 + 2i and 5 - 7i. Add, subtract, multiply, and divide these two numbers. During this exercise, the complex numbers had to be typed four times. To reduce this, assign each number to a variable. For the previous exercise, this results in: >> >> >> >>
z y1 y3 y4
= = = =
−3 + 2*i; w = 5 − 7*i; z + w; y2 = z − w; z * w; z / w; y5 = w \ z;
Formally, there is no need to declare (i.e. define the name, size and type of) a new variable in Matlab. A variable is simply created by an assignment, e.g. z = -3 + 2*i. Each newly created numerical variable is always of the double type, i.e. real numbers are approximated with the highest possible precision. You can change the type by converting to e.g. the single type.1 In some cases, e.g. when handling huge matrices occupying large amounts of memory (and precision is not very important), this might be a way to proceed. Also, when only integers are requires, it might be useful to convert from the double representations to an integer type, e.g. int32. Note that integer numbers are represented exactly, no matter which integer type is being used, as long as its value lies within the range of the integer type. Bear in mind that undefined values can not be assigned to variables. So, the following is not possible: >> clear x; >> f = xˆ2 + 4 * sin(x)
% to make sure that x does not exist
It becomes possible by: >> x = pi / 3;
f = xˆ2 + 4 * sin(x)
Variable names begin with a letter, followed by zero or more letters, numbers or underscores. Matlab recognizes only the first 63 characters of a name. 1 A variable a is converted into a different type by performing e.g. a = single(a) or a = int32(a). Note that Matlab all too eagerly reverts your singles and integers back to the default doubles.
2.1. Matlab as a calculator
14
Exercise 2.3. Here are some examples of different types of Matlab variables. You do not need to understand them all now, since you will learn more about them during the course. Create them manually in Matlab: >> this is my very simple variable today = 5 >> >> >> >> >>
2t = 8 M = [1 2; 3 4; 5 6] c = 'E' str = 'Hello world' m = ['J','o','h','n']
% % % % % % %
check what happens; the name is very long What are the problems here? a matrix a character a string Can you guess what this is?
Check the types by using the command whos. Use clear to remove a variable from the workspace. As you already know, Matlab variables can be created by an assignment. There are also a number of built-in variables, e.g. pi, eps and i, summarized in Table 2.1. In addition to creating variables by assigning values to them, another possibility is to copy one variable, e.g. b, into another, e.g. a. In this way, the variable a is automatically created (if a already existed, its previous value and type are lost): >> b = 10.5; >> a = b;
A variable can also be created by the evaluation of an expression, >> a = 10.5;
c = aˆ2 + sin(pi*a)/4;
or by loading data from text or ‘*.mat’ files. If min is the name of a function (see help min), then a defined as: >> b = 5; c = 7; >> a = min (b,c);
% create a as the minimum of b and c
will call that function, with the values b and c as parameters, and the result of this function (its return value) will be written (assigned) into a. So, variables can be created as results of the execution of built-in or user-defined functions (you will learn more how to built your own functions in section 6.1). Important: do not define variables with names that are already in use as function names (for instance mean or error) or as built-in variable names,2 because from this point on you cannot access the function or built-in variable anymore. For example, try >> mean([4 6]) ans = 2 There is always one √ exception √to the rule: the variables i and j are often used as counters in loops, while they are also used as i = −1, j = −1. As mentioned before, use 1i and 1j to ensure that you are dealing with the imaginary unit.
2.2. Exercises
15
5 >> mean=3 mean = 3 >> mean([4 6]) ??? Index exceeds matrix dimensions.
At the second calling, mean is a variable rather than the function mean. Note that Matlab does not warn you of potential conflicts. If you are going to use a suspicious variable name, use help to find out if the name is already in use. Variable name ans pi eps inf nan or NaN i or j nargin/nargout realmin/realmax
Value/meaning the default variable name used for storing the last result π = 3.14159... the smallest positive number that added to 1 makes a result larger than 1 representation for positive infinity, e.g. 1/0 representation for not-a-number, e.g. 0/0 √ i = j = −1 (Note: better use 1i in case the variable i is used) number of function input/output arguments used the smallest/largest usable positive real number: 1.7977e+308 / 2.2251e−308 Table 2.1: Built-in variables in Matlab.
2.2
Exercises
Exercise 2.4. Define the format in Matlab such that empty lines are suppressed and the output is given with 15 digits. Calculate: >> pi >> sin(pi)
Note that the answer is not exactly 0. Use the command format to put Matlab in its standardformat.
Chapter 3 Mathematics with vectors and matrices
The basic element of Matlab is a two-dimensional matrix. Special cases are: • a (1 × 1) matrix, i.e. a scalar or a single number; • a (1 × n) matrix, i.e. a row vector; • a (n × 1) matrix, i.e. a column vector. Note that Matlab may behave differently depending on the input, whether it is a number, a vector or a two-dimensional (or more-dimensional) matrix. Readers not familiar with vectors and matrices are advised to read the appendix at the end of this chapter before continuing.
3.1 3.1.1
Vectors Row vectors
Row vectors are lists, bracketed by [ ], of numbers separated either by commas or spaces. They are examples of simple arrays. Their entities are referred to as elements or components. In Matlab the first element always has index 1. The number of entries is known as the length of the vector, as returned by the command length. >> v = [−1 sin(3) 7] v = −1.0000 0.1411 >> length(v) ans = 3
7.0000
– 16 –
3.1. Vectors
17
A number of operations can be done on vectors. A vector can be multiplied by a scalar, or added/subtracted to/from another vector with the same length, or a number can be added/subtracted to/from every element in a vector. All these operations are carried out element-byelement. Vectors can also be built from already existing vectors. >> v = [−1 2 7]; w = [2 3 4]; >> z = v + w z = 1 5 11 >> vv = v + 2 vv = 1 4 9 >> t = [2*v, −w] ans = −2 4 14 −2 −3
% an element−by−element sum
% add 2 to all elements of vector v
−4
To display or change a particular element, >> v(2) = −1 v = −1 −1 >> w(2) ans = 3
% change the 2nd element of v 7 % display the 2nd element of w
Note that this requires rounded brackets.
3.1.2
Colon notation
Colon notation is an useful shortcut, used when producing row vectors (see Table 3.1 and help colon): >> 2:5 ans = 2 >> −2:3 ans = −2
3
4
5
−1
0
1
2
3
In general, first:step:last produces a row vector of entities, starting with the value first, incrementing by step, with the final value last (or the last increment before exceeding last). The default step size is one. >> 0.2:0.5:2.4 ans = 0.2000 0.7000 >> 3:8 ans = 3 4 5 >> −3:3:10
1.2000
6
7
1.7000 2.2000 % default step size 8
3.1. Vectors ans = −3 0 3 >> 1.5:−0.5:−0.5 ans = 1.5000 1.0000 >> 10:3:20 ans = 10 13 16
18
6
9 % negative step is also possible 0.5000
0 −0.5000 % last value is not part of the series
19
Given an array, one can easily evaluate a function for every element: >> x = 1:9; >> y = sqrt(x) y = 1.0000 1.4142
3.1.3
1.7321
2.0000
2.2361
2.4495
2.6458
2.8284
3.0000
Extracting and appending parts of a vector
Parts of vectors can be extracted by using colon notation: >> r = [−1:2:6, 2, 3, −2] r = −1 1 3 5 >> r(3:6) ans = 3 5 2 3 >> r(1:2:5) ans = −1 3 2 >> r(5:−1:2)
% −1:2:6 2
=>
−1
1
3
5
3 −2 % get elements 3 through 6 (inclusive) of r
% get elements 1, 3 and 5 of r
% What will you get here?
Matlab allocates memory for all variables on the fly. This allows you to increase the size of a vector simply by assigning a value to an element exceeding the current range. >> x = linspace(21,25,5) % create 5 equidistant values from 21 to 25 x = 21 22 23 24 25 >> x(8) Index exceeds matrix dimensions. >> x(8) = −9 x = 21 22 23 24 25 0 0 −9
In the last line the array size is extended from 5 to 8, element 8 is assigned the value -9, and the elements intermediate between 5 and 8 are set to zero. Note that this easy approach to resizing arrays might appear user-friendly, but it complicates the tracking of out-of-range errors. When working with steadily growing arrays, the repeated resizing becomes a time consuming business; it is therefore recommended to directly define arrays with their intended maximum sizes.
3.1. Vectors
3.1.4
19
Column vectors and transposing
To create column vectors, you should separate entries by new lines or semicolons ’;’: >> z = [1 7 7]; z = 1 7 7 >> u = [−1; 3; 5] u = −1 3 5
The operations applied to row vectors can be applied to column vectors as well. You can not, however, add a column vector to a row vector (which also makes no sense mathematically). To ’add’ a column vector to a row vector (of the same length) or vice versa, you need an operation called transposing which converts a column vector into a row vector or vice versa: >> transpose(u) ans = −1 3 5 >> u' ans = −1 3 5 >> v = [−1 2 7]; >> u + v Matrix dimensions must agree. >> u' + v ans = −2 5 12 >> u + v' ans = −2 5 12
% u is a column vector, transposing yields a row
% prime as (potentially dangerous) short−hand
% v is a row vector % you can not add a column vector to a row vector
For a complex vector z, the shorthand z’ returns the conjugate transpose. For instance: >> z = [1+2i, −1+i] z = 1.0000 + 2.0000i >> transpose(z) ans = 1.0000 + 2.0000i −1.0000 + 1.0000i >> z' ans = 1.0000 − 2.0000i −1.0000 − 1.0000i >> z.' ans = 1.0000 + 2.0000i
−1.0000 + 1.0000i % the transpose
% the conjugate transpose
% shorthand transpose
3.1. Vectors
20
−1.0000 + 1.0000i
3.1.5
Products, divisions and powers of vectors
You can now compute the inner product (a.k.a. dot product) of two vectors x and y of the same length, x · y, in a simple way: >> u = [−1; 3; 5] >> v = [−1; 2; 7] >> u * v
% % % %
a column vector a column vector you can not multiply a column vector by a column vector
Error using * Inner matrix dimensions must agree. >> u' * v % this is the inner product ans = 42 >> dot(u,v) % this is also the inner product ans = 42
Given two vectors x and y of the same length n, an element-wise multiplication yields a vector with elements x1 y1 , x2 y2 , . . . , xn yn . For instance: >> u .* v 1 6 35 >> sum(u.*v) ans = 42 >> z = [4 3 1]; >> sum(u'.*z) ans = 10 >> u'*z' ans = 10 >> z*u ans = 10
% this is an element−by−element multiplication
% yet another way to compute the inner product
% z is a row vector % this is the inner product
% and this is the inner product
% and this is the inner product
Try what happens for u*v’, u’.*v, u*z and u.*z; the result is known as the dyadic product. Mathematically, the division of one vector by another vector is an undefined operation. In Matlab, however, the operator ./ is introduced to perform an element-wise division for vectors of the same size and type: >> x = 2:2:10 x = 2 4 >> y = 6:10 y = 6 7 >> x./y
6
8
10
8
9
10
3.2. Matrices
21
ans = 0.3333 0.5714 0.7500 0.8889 1.0000 >> z = −1:3 z = −1 0 1 2 3 >> x./z % division 4/0, resulting in infinity Warning: Divide by zero. % recent versions of matlab do not warn :−( ans = −2.0000 Inf 6.0000 4.0000 3.3333 >> z./z % division 0/0, resulting in 'not any number' Warning: Divide by zero. ans = 1 NaN 1 1 1
The operator ./ can also be used to divide a scalar by a vector: >> x=1:5; 2/x % this is not possible Error using / Matrix dimensions must agree. >> 2./x % but this is! ans = 2.0000 1.0000 0.6667 0.5000 0.4000
Exercise 3.1. Get acquainted with operations on row and column vectors. Perform, for instance: • Create a vector consisting of the even numbers between 21 and 47. • Let x = [4 5 9 6]. – Subtract 3 from each element. – Add 11 to the odd-index elements. – Compute the square root of each element. – Raise each element to the power 3. • Create a vector x with the elements: – 2, 4, 6, 8, ..., 16; – 9, 7, 5, 3, 1, −1, −3, −5.
• Given x = [2 1 3 7 9 4 6], explain what the following commands do: – – – –
x (3) x (1:7) x (end) x (1:end)
– – – –
x (1:end-1) x (2:2:6) x (6:-2:1) x (end/2:-3:2)
– – – –
x (:) sum(x) mean(x) min(x)
3.2
Matrices
Row and column vectors are special types of matrices. An (n × k) matrix is a rectangular collection of numbers having n rows and k columns. Defining a matrix in Matlab is similar to defining a vector. The generalisation is straightforward once you appreciate that a matrix is a column of row vectors or a row of column vectors. Like before, commas or spaces are used to separate elements in a row, and semicolons are used to separate elements in a column. For example,
3.2. Matrices
22
>> A = [1 2 3 ; 4 5 6 ; 7 8 9] A = 1 2 3 4 5 6 7 8 9 >> B = [ [ 1 ; 4 ; 7 ] [ 2 ; 5 ; 8 ] [ 3 ; 6 ; 9 ] ] B = 1 2 3 4 5 6 7 8 9
% row by row input
% column by column
Other examples are, for instance: >> A2 = [1:4; −1:2:5] A2 = 1 2 3 −1 1 3 >> A3 = [1 3 −4 7] A3 = 1 3 −4 7
4 5
Conversely, a row vector is a (1×k) matrix and a column vector is an (n×1) matrix. Transposing a vector changes it from a row to a column or the other way round. For a matrix, the transpose operation interchanges the rows with the corresponding columns, as in the example: >> A2 A2 = 1 −1
2 1
>> A2' ans = 1 −1 2 1 3 3 4 5 >> size(A2)
3 3
4 5 % transpose of A2
% returns the size (dimensions) of A2: % 2 rows and 4 columns
ans = 2 4 >> size(A2') ans = 4 2
Command A(i,j) A(:,j) A(i,:) A(k:l,m:n) A(isnan(A)) v(i:j)
Result Aij j-th column of A i-th row of A ((l − k + 1) × (n − m + 1)) matrix with elements Aij for k ≤ i ≤ l, m ≤ j ≤ n functions like isnan return a logical (boolean) array; see section 5.1.1 ’vector-part’ (vi , vi+1 , . . . , vj ) of vector v Table 3.1: Manipulation of (groups of) matrix elements.
3.2. Matrices
23
Command n = rank(A) x = det(A) x = size(A) x = trace(A) x = norm(v) C = A + B C = A - B C = A * B C = A .* B C = A^k C = A.^k C = A’ C = A.’ C = A ./ B X = A \ B X = B / A C = inv(A) C = null(A) C = orth(A) L = eig(A) [Q,L] = eig(A) S = svd(A) [U,S,V] = svd(A) x = linspace(a,b,n) x = logspace(a,b,n) A = eye(n) A = zeros(n,m) A = ones(n,m) A = diag(v) v = diag(A) X = tril(A) X = triu(A) A = rand(n,m) A = randn(n,m) spy(A) v = max(A) v = max(A,[],dim) B = max(A,x) v = min(A), v = min(A,[],dim) v = sum(A), v = sum(A,dim)
Result n becomes the rank of matrix A x becomes the determinant of matrix A x becomes a row-vector with 2 elements: the number of rows and columns of A x becomes the trace (sum of diagonal elements) of matrix A x becomes the Euclidean length of vector v sum of two matrices subtraction of two matrices multiplication of two matrices ’element-by-element’ multiplication (A and B are of equal size) power of a matrix (k ∈ Z; can also be used for A−1 ) ’element-by-element’ power of a matrix the conjugate transpose of a matrix; A∗ the transpose of a matrix; AT ’element-by-element’ division (A and B are of equal size) finds the solution in the least squares sense to the system of equations AX = B finds the solution of XA = B, analogous to the previous command C becomes the inverse of A C is an orthonormal basis for the null space of A obtained from the singular value decomposition C is an orthonormal basis for the range of A L is a vector containing the (possibly complex) eigenvalues of a square matrix A produces a diagonal matrix L of eigenvalues and a full matrix Q whose columns are the corresponding eigenvectors of a square matrix A S is a vector containing the singular values of a rectangular matrix A S is a diagonal matrix with nonnegative diagonal elements in decreasing order; columns of U and V are the accompanying singular vectors of A generates a vector x of n equally spaced points between a and b generates a vector x starting at 10a and ended at 10b containing n values A is an (n × n) identity matrix A is an (n × m) matrix with zeros (default m = n) A is an (n × m) matrix with ones (default m = n) results in a diagonal matrix with the elements v1 , v2 , . . . , vn on the diagonal results in a vector equivalent to the diagonal of A X is lower triangular part of A X is upper triangular part of A A is an (n × m) matrix of elements drawn from a uniform distribution on [0, 1] A is an (n × m) matrix of elements drawn from a standard normal distribution Plots the non-zero elements of A v is a vector of the maximum values of the columns in A v is a vector of the maximum values along dimension dim in A (1=column, 2=rows) elements in B equal the corresponding element(s) in A or x, whichever is bigger ditto - with minimum ditto - with sum
Table 3.2: Frequently used matrix operations and functions.
3.2. Matrices
3.2.1
24
Special matrices
There are a number of built-in commands to generate frequently used matrices with userspecified sizes, see Table 3.2. A few examples are given below: >> E = [] E = [] >> size(E) ans = 0 0 >> I = eye(3); I = 1 0 0 0 1 0 0 0 1 >> r = [1 3 −2]; R = diag(r) R = 1 0 0 0 3 0 0 0 −2 >> A = [1 2 3; 4 5 6; 7 8 9]; >> diag(A) ans = 1 5 9 >> B = ones(3,2) B = 1 1 1 1 1 1 >> C = zeros (size(B')) C = 0 0 0 0 0 0 >> D = rand(2,3)
% an empty matrix of (0 x 0) elements!
% the (3 x 3) identity matrix
% create a diagonal matrix with r on the diagonal
% extracts the diagonal entries of A
% a matrix of all zeros of the size given by B'
% a matrix of random numbers; you will get a % different one!
D = 0.0227 0.9101 0.0299 0.0640 >> v = linspace(1,2,4) v = 1.0000 1.3333
3.2.2
0.9222 0.3309 % a vector is also an example of a matrix 1.6667
2.0000
Building matrices and extracting parts of matrices
It is often useful to build a larger matrix from a number of smaller ones: >> x = [4; −1], y = [−1 3] x = 4 −1 y = −1 3 >> X = [x y']
% X consists of the columns x and y'
3.2. Matrices
25
X = 4 −1 −1 3 >> T = [ −1 3 4; 4 5 6]; t = 1:3; >> T = [T; t] % add to T a new row, namely the row vector t T = −1 3 4 4 5 6 1 2 3 >> G = [1 5; 4 5; 0 2]; % G is (3 x 2); check with size(G) >> T2 = [T G] % join two matrices T2 = −1 3 4 1 5 4 5 6 4 5 1 2 3 0 2 >> T3 = [T; G ones(3,1)] % G is (3 x 2), T is (3 x 3) T3 = −1 3 4 4 5 6 1 2 3 1 5 1 4 5 1 0 2 1 >> T3 = [T; G']; % this is also possible T3 = −1 3 4 4 5 6 1 2 3 1 4 0 5 5 2 >> [G' diag(5:6); ones(3,2) T] % you can join many matrices ans = 1 4 0 5 0 5 5 2 0 6 1 1 −1 3 4 1 1 4 5 6 1 1 1 2 3
A part of a matrix can be extracted from a matrix in a similar way as the extraction of parts of vectors. Each element in a matrix is indexed by the row and column to which it belongs. In mathematics the element in the i-th row and the j-th column of the matrix A is denoted as Aij , whereas Matlab uses the A(i,j) notation. >> A = [1:3; 4:6; 7:9] A = 1 2 3 4 5 6 7 8 9 >> A(1,2), A(2,3), A(3,1) ans = 2 ans = 6 ans = 7 >> A(4,3) % this is not possible: A is a (3 x 3) matrix! ??? Index exceeds matrix dimensions. >> A(2,3) = A(2,3) + 2*A(1,1) % change the value of A(2,3) A = 1 2 3
3.2. Matrices 4 7
26 5 8
8 9
It is (too) easy to automatically extend the size of a matrix. For the matrix A above this can be done e.g. as follows: >> A(5,2) = 5 A = 1 2 4 5 7 8 0 0 0 5
% assign 5 to the position (5,2); the uninitialized % elements of A become zeros 3 8 9 0 0
The newly introduced zero-valued elements of the matrix can be assigned a value, e.g. >> A(4,:) = [2, 1, 2]; >> A(5,[1,3]) = [4, 4]; >> A A = 1 2 3 4 5 8 7 8 9 2 1 2 4 5 4
% assign vector [2, 1, 2] to the 4th row of A % assign: A(5,1) = 4 and A(5,3) = 4 % what does the matrix A look like now?
Different parts of the matrix A can now be extracted: >> A(3,:) ans = 7 8 >> A(:,2) ans = 2 5 8 1 5 >> A(1:2,:) ans = 1 2 4 5 >> A([2,5],1:2) ans = 4 5 4 5
% extract the 3rd row of A 9 % extract the 2nd column of A
% extract the 1st and 2nd row of A 3 8 % extract a part of A
As you have seen in the examples above, it is possible to manipulate (groups of) matrix-elements. The commands are summarized in Table 3.1. The concept of an empty matrix [] is also very useful in Matlab. For instance, columns or rows can be removed from a matrix by ‘filling’ them with an empty matrix. Try for example: >> C = [1 2 3 4; 5 6 7 8; 1 1 1 1]; >> D = C; % the entire matrix C is copied to D
3.2. Matrices >> D(:,2) = [] >> C ([1,3],:) = []
3.2.3
27 % remove the 2nd column % remove rows 1 and 3
Matrix operations
Matrix-matrix multiplication are straightforward: use the multiplication sign, as in C = A * B, and Matlab applies the usual rules of linear algebra, X Cij = Aip Bpj . p
Keep in mind that this multiplication only works if the number of columns in A equals the number of rows in B. The resulting matrix C contains the same number of rows as A and the same number of columns as B. >> b = [1 3 −2]; >> B = [1 −1 3; 4 0 7] B = 1 −1 3 4 0 7 >> b * B % not possible: b is (1 x 3), B is (2 x 3) ??? Error using ==> * Inner matrix dimensions must agree. >> b * B' % ok: (1 x 3) * ( 3 x 2 ) −> (1 x 2) ans = −8 −10 >> B' * ones(2,1) % a (2 x 1) matrix filled with one−s ans = 5 −1 10 >> C = [3 1; 1 −3]; >> C * B ans = 7 −3 16 −11 −1 −18 >> Cˆ3 % this is equivalent to C*C*C ans = 30 10 10 −30 >> ( ones(3,4) / 4 ) * diag(1:4) ans = 0.2500 0.5000 0.7500 1.0000 0.2500 0.5000 0.7500 1.0000 0.2500 0.5000 0.7500 1.0000
Table 3.2 lists frequently used matrix operations and functions, including all usual manipulations encountered in linear algebra. The element-wise dot-operations, as discussed above for vectors, also work for matrices. A couple of examples: >> B = [1 −1 3; 4 0 7] B =
3.3. Exercises
28
−1 3 0 7 >> B2 = [1 2; 5 1; 5 6]; >> B = B + B2 % Matrix dimensions must agree >> B = B + B2' % B = 2 4 8 6 1 13 >> B−2 % ans = 0 2 6 4 −1 11 >> ans = B/4 % ans = 0.5000 1.0000 2.0000 1.5000 0.2500 3.2500 >> 4/B % Error using / Matrix dimensions must agree. 1 4
>> 4./B
add two matrices
subtract 2 from all elements of B
divide all elements of the matrix B by 4
this is not possible
% this is possible; % equivalent to: 4*ones(size(B))./ B
ans = 2.0000 1.0000 0.5000 0.6667 4.0000 0.3077 >> C = [1 −1 4; 7 0 −1]; >> B .* C % ans = 2 −4 32 42 0 −13 >> ans.ˆ3 − 2 % ans = 6 −66 32766 74086 −2 −2199 >> ans ./ B.ˆ2 % ans = 1.0e+03 * % 0.0015 −0.0041 0.5120 2.0579 −0.0020 −0.0130
3.3
add two matrices
multiply element−by−element
for all elements: raise to power 3 and subtract 2
element−by−element division by squared elements multiplication factor for all elements
Exercises
Exercise 3.2. Create a vector containing five elements such that the elements are equally spaced when you take the logarithm of the vector. Exercise 3.3. Perform the following exercises: • Create a vector x with the elements: – 1, 1/2, 1/3, 1/4, 1/5; – 0, 1/2, 2/3, 3/4, 4/5. Realize this by dividing a vector y by a vector z.
3.3. Exercises
• Create a vector x with the elements xn =
29 (−1)n for n = 1, 2, 3, ..., and determine the sum 2n − 1
of the 100-element vector (≈ −π/4). • Given a vector x, provide the Matlab expressions that will return for all elements x: – ln(2 + x + x2 ) – cos(x2 ) + sin(x2 ) – cos2 (x) + sin2 (x) – ex (1 + cos(3x)) – arctan(x) Test your expressions for x = 1:0.2:2.
Exercise 3.4. Use the knowledge on computing the inner product to find: 1. the Euclidean length of the vector x = (2, 1, 3, 7, 9, 4, 6), defined as |x| = the Matlab command norm to verify your answer.
qP ( i x2i ). Use
2. the angle between two vectors x and y, defined as α = arccos[(x · y)/(|x| |y|)]. Compute the angles between the vectors • x = (3,2,1) and y = (1,2,3), • x = 1:5 and y = 6:10.
Exercise 3.5. Define the matrix A = [1:4; 5:8; 1 1 1 1]. Predict and check the result of the following operations (starting with the first column): • x = A(:,3)
• y = A(3:3,1:4)
• A(1,1) = 9 + A(2,3)
• C = A([1,3],2)
• B = A(1:3,2:2)
• A(2:3,1:3) = [0 0 0; 0 0 0] • A(2:3,1:2) = [1 1; 3 3]
• A = [A; 2 1 7 7; 7 7 4 5] • D = A([2,3,5],[1,3,4]) • D(2,:)
= []
Exercise 3.6. Define the matrices T = [ 3 4; 1 8; -4 3] and A = [diag(-1:2:3) T; -4 4 1 2 1]. Perform the following operations on the matrix A: • • • • • •
extract a vector consisting of the 2nd and 4th elements of the 3rd row find the minimum of the 3rd column find the maximum of the 2nd row compute the sum of the 2nd column compute the mean of the 1st and 4th rows extract the submatrix consisting of the 1st and 3rd rows and all columns
3.3. Exercises
30
• extract the submatrix consisting of the 1st and 2nd rows and the 3rd, 4th and 5th columns • compute the total sum of the 1st and 2nd rows • add 3 to all elements of the 2nd and 3rd columns
Exercise 3.7. Let A = [2 4 1; 6 7 2; 3 5 9]. Provide the commands that: • • • •
assign the first row of A to a vector x; assign the last 2 rows of A to a vector y; add up the columns of A; add up the rows of A;
Exercise 3.8. Let A = [2 7 9 7; 3 1 5 6; 8 1 2 5]. Explain the results of the following commands: • A’
• fliplr (A)
• sum (A,2)
• A(:,[1 4])
•
• min (A)
• A(1,:)’
• A([2 3], [3 1]) • reshape (A,2,6) • A(:)
• flipud (A)
• [A • • • •
A(end,:)] [A; A(1:2,:)] sum (A) sum (A’) mean (A) mean (A’)
• mean (A,2) • max (A’)
• min (A(:,4))
• [min(A)’ max(A)’] • max (min(A))
• [ [A; sum (A)] [ sum (A,2); sum (A(:)) •
•
•
•
•
•
• •
] ] assign the even-numbered columns of A to an array B assign the odd-numbered rows to an array C convert A into a 4-by-3 array compute the reciprocal of each element of A compute the square-root of each element of A remove the second column of A add a row of all 1’s at the beginning and at the end swap the 2nd row and the last row
Exercise 3.9. Given the vectors x = [1 3 7] and y = [2 4 2] and the matrices A = [3 1 6; 5 2 7] and B = [1 4; 7 8; 2 2], determine which of the following statements can be correctly executed (and if not, try to understand why not) and explain their results:
3.4. Appendix
• x + y • x + A
• x’ + y
• A - [x’ • [x;
y’] y] + A
31
• [x;
• B * A
• B ./ x’
•
• A’ .* B
• 2 / A
• • •
y’] [x; y] A - 3 A + B B’ + A
• A .* B • 2 * B
• 2 .* B
• B ./ [x’
x’]
• ones(1,3) * A • ones(1,3) * B
Exercise 3.10. Perform all operations from Table 3.2, using some matrices A and B, vector v and scalars k, a, b, n, and m. Exercise 3.11. Let A be a square 6-by-6 matrix. 1. Create a matrix B whose elements are the same as those of A except for the entries on the main diagonal: the diagonal of B should consist of one-s. 2. Create a tridiagonal matrix T whose three diagonals are taken from the matrix A. Hint: you may want to use the commands triu, tril and diag.
Exercise 3.12. Let A be a random (5×5) matrix and let y be a random (5×1) vector. Given that Ax = y, solve the vector x. Explain the difference between the operator \ (a.k.a. mldivide), the operator /, and the command inv. Having found y, verify whether Ax − y is close to a zero vector. Exercise 3.13. Let A by a 6 × 8 random matrix. Normalize the columns of the matrix so that all columns of the resulting matrix, say B, have the Euclidean norm (length) equal to 1. Next, calculate the angles between the consecutive columns of the matrix B. Exercise 3.14. Try what happens upon entering a(3,3,3) = 1.
3.4
Appendix
In a three-dimensional space, the position of a point relative to the origin is represented by three numbers, the x, y and z coordinates of that point. A convenient way of collecting these coordinates is in a (3 × 1) column vector, r1 x r = r2 = y . r3 z
3.4. Appendix
32
Likewise, for a cloud of N particles r1,1 R = (r1 , r2 , . . . , rN ) = r2,1 r3,1
one collects the coordinates are into a (3 × n) matrix, r1,2 r1,n r2,2 . . . r2,n . r3,2 r3,n
The i-th column of R contains the three coordinates of the i-th point, the third row of r contains the z-coordinates of all N points, and the y coordinate of the i-th point is contained in R2i , etc. The distance |r| from point r to the origin is readily evaluated using Pythagoras’ theorem, which in three-dimensions reads as |r|2 = x2 + y 2 + z 2 = r12 + r22 + r32 . The angle γ between the vectors running from the origin to points i and j, respectively, follows from |ri ||rj | cos γ = r1,i r1,j + r2,i r2,j + r3,i r3,j . Note that the calculation of the length |ri | is a special case of the latter expression, with i = j and γ = 0. The sum of products on the r.h.s. is known as the inner product or dot product, with the short-hand notation ri · rj =
K X
rk,i rk,j ,
k=1
where the summation, take on other values).
P
, runs from 1 to K = 3 for 3D space (while in other contexts K can
Suppose now that we want to rotate the entire cloud of points around the z-axis over an angle α. For a point with old coordinates ro , its new coordinates rn read as xn = cos α · xo − sin α · y o ,
y n = sin α · xo + cos α · y o , zn = zo.
Every new coordinate is obtained by a linear we write n r1 cos α · r1o + − sin α · r2o n r2 = sin α · r1o + cos α · r2o 0 · r2o 0 · r1o + r3n
combination of the old coordinates. To stress this, + 0 · r3o + 0 · r3o . + 1 · r3o
These equations follow the pattern X rjn = Ajk rko , k
where j and k take the values 1, 2 and 3 (for x, y and z) and A is a collection of nine elements sorted in three rows (with ordinal number j) and three columns (with ordinal number k): a matrix. This is more commonly written as the matrix-vector multiplication n o r1 cos α − sin α 0 r1 r2n = sin α cos α 0 r2o , 0 0 1 r3n r3o
3.4. Appendix
33
or even shorter, rn = Aro , where the dimensions follow the rule (3 × 1) ← (3 × 3)(3 × 1). To rotate the entire cloud of particles, X o n , = Ajk rki rji k
or in short-hand Rn = ARo , where the dimensions follow the rule (3 × N ) ← (3 × 3)(3 × N ). The above indexed expressions provide the general rule for matrix multiplication, with dimensions (P × N ) ← (P × Q)(Q × N ). We can rotate the rotated cloud once more, to Rm , using a second (3 × 3) rotation matrix B. The new coordinates are then related to the old (pre-rotation coordinates) by X X X n o , Blj rji = Blj Ajk rki rlim = j
j
k
or Rm = BRn = BARo . The two consecutive rotations can be combined into a single rotation, X o , Clk rki rlim = k
with Clk =
X
Blj Ajk .
j
Note that this relation again follows the general rule for matrix multiplication. For any given rotation matrix A, it is possible to construct a rotation matrix B such that all points return to their original positions, rlim = rlio , for all l and i. In that case, C = BA is the identity matrix, 1 0 0 C = 0 1 0 , 0 0 1 or in short-hand C = I, and B acts as the inverse of A, B = A−1 . Note that, in general, the elements Bij = (A−1 )ij of A−1 are not simply 1/Aij but have to be solved from the set of equations X Bij Ajk = Iik . j
3.4. Appendix
34
Rotation matrices have the special property that their inverse is equal to their transposed, i.e. the matrix obtained by swapping rows and columns, (A−1 )ij = Aji , or for short A−1 = AT , while most matrices require much more work to find their inverse. Take an asymmetric object, like your laptop, and rotate it by 90◦ around a space-based x axis (e.g. the long axis of your desk), followed by a 90◦ rotation around a space-based y axis (e.g. the short axis of your desk) Next, start with the laptop (or your neighbour’s) in the same initial orientation and execute the two rotations in the reverse order. Note how the two final orientations differ; in other words, AB 6= BA. This reveals an important property of matrices: the order of multiplication matters, unlike the multiplication behaviour of ordinary numbers (‘scalars’). One therefore must take care when manipulating matrices, by hand or in Matlab, to conserve the correct order. For two consecutive rotations, the order becomes irrelevant when both rotations rotate around the same axis, in which case the two matrices are said to commute. Once you understand matrices, you will recognize them everywhere: in the weighted combination of the grades you scored on tests into the final grade for a course, in the calculation of nutrional values (kcals, grams of fibers, fats and proteins) from your diet composition (half a liter of milk contributing xxx per 100 ml, four slices of bread contributing xxx per slice, etc), in the solution of coupled linear equations, y = Ax
→
x = A−1 y,
and so on. Matrices have many more useful properties, for which we refer the reader to the literature. Some of these properties are listed in Table 3.2.
Chapter 4 Scripts
4.1
Script m-files
Thus far, all Matlab commands were entered at the Matlab prompt and executed immediately. This becomes inefficient when a problem becomes more complicated. A solution is to store the commands in script m-files. M-files are useful e.g. when the number of commands increases or when you want to repeat the same series of commands with different starting values. Formally, a script is an external file that contains a sequence of Matlab commands (statements).1 When you run a script, the commands in it are executed as if they have been entered through the keyboard.
4.2
Creating and running a script
To generate an example script m-file: • Type edit sinplot in the workspace or use the mouse to open a ‘New Script’. • Enter the lines listed below %creates a plot of the sine function x = 0 : 0.1 : 6.3; y = sin(a*x); plot(x,y); title('Plot of y = sin(x)'); 1
Note the difference between script and function m-files, as discussed in more detail in Chapter 6: a script has neither input nor output parameters, and the variables in a script reside in the regular workspace rather than in a function-specific workspace.
– 35 –
4.3. Exercises
36
• Save the file under the name ‘sinplot’ (Matlab will add the extension ‘.m’) in a directory (folder) of your choice. • Run the script by typing in the Matlab prompt: a = 3; sinplot
Alternatively, type a = 3; in the command window and then press F5 or click on the ‘Run’ button. You might experience problems if your path is not set correctly. The path is the collection of directories (folders) that Matlab scans for programs to be run, see Section 1.4. If you saved your script in, say, Myfolder, you can make this your working directory in Matlab, >> cd Myfolder
or add this directory to the path using the ‘Set Path’ button. • Try help sinplot to appreciate the usefulness of including comment lines at the top of an m-file. Note that the sinplot script affects the workspace: clear a = 3; who Your variables are: a sinplot who Your variables are: a x y
% all variables are removed from the workspace
The trivial variable names x and y may may well be in use already, in which case invoking the script overwrites their values. Note that the script also relies on the value of a in the workspace, and will abort with an error if a was not defined before invocation. Undesirable side-effect are likely to occur when scripts change variables (here: x and y) other than the ‘input’ arguments (here: a), and even these restricted changes can have undesirable consequences. Since scripts create and change variables in the workspace without warning, they may easily introduce bugs that are hard to track down. Hence, it is important to keep in mind that the commands within a script have access to all variables in the workspace and all variables created in a script become part of the workspace. It is highly recommended, therefore, to use script m-files sparingly and to resort to function m-files to solve recurring sub-problems, see Chapter 6, as functions do not have access to the workspace. We will have much more to say on plotting graphs in section 11.
4.3
Exercises
Exercise 4.1. 2 Write a script that, for given √ a, b and c, solves the quadratic equation ax + bx + c = 0, i.e. returns the roots x = (−b ± b2 − 4ac)/(2a).
Chapter 5 Control flow
Control flow deals with the conditional and/or repeated execution of blocks of commands.
5.1
Logical and relational operators
To use control flow commands, it is necessary to perform operations that result in logical values: TRUE or FALSE. In Matlab these are denoted as 1 (true) and 0 (false). Table 5.1 shows the relational and logical operations; another way to get to know more about them is to type help relop. The relational operators <=, <, >, >=, == and ∼= are used to compare two arrays of the same size element-by-element, or to compare all elements in one array against the same scalar. The logical operators &, |, xor, any and all combine collections of two or more logicals into a smaller number of logicals, while the logical operator ∼ is used for negation ( true ⇆ false). Important: the operations & and | have equal precedence in Matlab, which means that these operators associate from right to left (unlike regular arithmetic). A common situation is:1 >> b = >> 1 | ans = 1 >> ( 1 ans = 0 >> 1 | ans = 1
10; b > 0
& 0
% evaluated from right to left
| b > 0 ) & 0 ( b > 0
& 0 )
% this is equivalent to the first evaluation
You are strongly advised to always use brackets to impose a desired order of evaluations.2 1 2
Note that the relational operation b > 0 is evaluated before the logical operations. This is also highly recommended for numerical operations, e.g. a = 4 / 5 * 3 .
– 37 –
5.1. Logical and relational operators Command a = (b > c) a = (b == c) a = (b ∼= c) a = ∼b a = (b & c) a = (b | c) a = xor(b,c)
Result a becomes a becomes a becomes a becomes a becomes a becomes a becomes
1 1 1 1 1 1 1
38
if if if if if if if
b is larger than c and a becomes 0 otherwise. b is equal to c and a becomes 0 otherwise. b is not equal to c and a becomes 0 otherwise. b equals 0 and a becomes 0 otherwise. both b and c are true and a becomes 0 otherwise. b and/or c are true and a becomes 0 otherwise. either b or c is true and a becomes 0 otherwise.
Table 5.1: Relational and logical operations.
5.1.1
Logical indexing
The application of relational operators to an array returns an array of logicals, >> i = i = 5 >> j = j = 1x10 1
5:14; 6 7 8 ( mod(i,2) == 1 ) logical array 0 1 0 1
0
9
1
10 11 12 13 14 % brackets added for clarity
0
% matlab warning: these are not floats 1 0
The array j can be used to access selected elements of i, by the method of ‘logical indexing’: >> i(j)
% show the elements of i for which % the matching element of j is true.
ans = 5 7 9 >> i(j) = i(j) + 50 i = 55 6 57
11
13 % modify the selected elements
8
59
10
61
12
63
14
Note that an array of numerical zeros and ones differs from a array of logical zeros and ones: >> i = 5:14; >> j = ( mod(i,2) == 1 j = 1 0 1 0 1 >> k = ( mod(i,2) ) k = 1 0 1 0 1 >> i(k) = i(k) + 50 Subscript indices must
) 0
1
0
1
0
%
logicals
0
1
0
1
0
%
floats
either be real positive integers or logicals.
For the latter line to work, the array k must first be converted into an array of logicals, which is realized with p = logical(k). In Matlab, any non-zero numerical value is ‘true’ and only absolute zero is ‘false’. The logical complement ∼ implicitly converts floats into logicals, but tricks like p = ∼∼k are better avoided: when you read your code again in a couple of months you will be confused by the double negation – does that not recover the original value? – and remove it, thereby ending up with a malfunctioning code.
5.1. Logical and relational operators
39
Whereas numerical zeros and ones can not be used for logical indexing, logical zeros and ones can be used for arithmetic operations (with ‘true’ acting as 1. and ‘false’ as 0.). In the above example, both i.*j and i.*k will yield the same output: odd numbers alternating with zeros. Note what happens when we turn k into an array of real positive integers by adding one, >> i = 5:14; >> k = mod(i,2) + 1 k = 2 1 2 >> i(k) 6 5 6 >> i(k) = i(k) + 50 i = 55 56 3
1
2
1
2
1
2
1
5
6
5
6
5
6
5
4
5
6
7
8
9
10
You probably expected the last line to increase elements 1 and 2 of i five times by 50, yielding the values 255 and 256, which clearly did not happen. The ten increments were indeed executed, but each of these calculations used a (copy of) the original values of i. If you want consecutive calculations on array elements to build on previous updates of these elements, you must write a loop (see below). Exercise 5.1. Exercise with logical and relational operators: 1. Predict and check the result of each of the operations of Table 5.1 for b = 0 and c = -1. 2. Predict and check the result of each logical operator for b = [2 31 -40 0] and c = 0. 3. Define two random vectors (randn(1,7)) and perform all logical operations, including xor, any and all.
Exercise 5.2. Exercise with logical and relational operators: 1. Let x = [1 5 2 8 9 0 1] and y = [5 2 2 6 0 0 2]. Execute and explain the results of the following commands: • x > y • y < x • x == y
• x <= y • y >= x • x | y
• x & (∼y) • (x > y) | (y < x) • (x > y) & (y < x)
2. Let x = 1:10 and y = [3 5 6 1 8 2 9 4 0 7]. The exercises here show the techniques of logical-indexing. Execute and interpret the results of the following commands: • (x > 3) & (x < 8) • x( x > 5 ) • y( x <= 4 )
• x( (x < 2) | (x >= 8) ) • y( (x < 2) | (x >= 8) ) • x( y < 0 )
Exercise 5.3. Let x = [3 16 9 12 -1 0 -12 9 6 1]. Provide the command(s) that will:
5.1. Logical and relational operators
40
• set the positive values of x to zero;
• set values that are multiples of 3 to 3 (make use of rem); • multiply the even values of x by 5; • extract the values of x that are greater than 10 into a vector called y;
• set the values in x that are less than the mean to 0; • set the values in x that are above the mean to their difference from the mean.
Exercise 5.4. Execute the following commands and try to understand how z is defined. >> >> >> >> >> >>
hold on x = −3:0.05:3; y = sin(3*x); subplot(1,2,1); plot(x,y); axis tight z = (y < 0.5) .* y; subplot(1,2,2); plot(x,y,'r:'); plot(x,z,'r'); axis tight hold off
Before moving on, check whether you now understand the following relations: >> >> >> >> >> >> >> >> >> >> >>
5.1.2
a = randperm(10); b = 1:10; b − (a <= 7) (a >= 2) & (a < 4) ∼(b > 4) (a == b) | b == 3 any(a > 5) any(b < 5 & a > 8) all(b > 2)
% random permutation % % % % % % % % %
subtracts from b a 0−1 vector, with 1 for a <= 7 and 0 otherwise returns ones at positions where 2 <= a < 4 returns ones at positions where b <= 4 returns ones at positions where a is equal to b and/or b is equal to 3 returns 1 when ANY of the a elements is larger than 5 returns 1 when (b < 5 & a > 8) yields at least one true returns 1 when ALL elements of b are larger than 2
The find command
Logical indexing allows one to extract those elements from a vector (or matrix) that satisfying a given condition, by using an array of logicals as the intermediate step. The same final result can be obtained using find, which returns the positions (indices) of the element(s) matching the condition: >> x = [1 1 3 4 1]; >> i = (x == 1) i = 1 1 0 >> y = x(i) y = 1 1 1 >> j = find(x == 1) j = 1 2 5 >> z = x(j) z = 1 1 1
% i holds: do the elements satisfy x == 1? 0
1
% j holds: which element(s) satisfy x == 1?
5.1. Logical and relational operators
41
Another example: >> x = −1:0.05:1; >> y = sin(x) .* sin(3*pi*x); >> plot (x,y, '−'); hold on >> k = find (y <= −0.1) k = 9 10 11 12 13 >> plot (x(k), y(k), 'ro'); >> r = find (x > 0.5 & y > 0) r = 35 36 37 38 39 >> plot (x(r), y(r), 'r*');
29
30
40
41
31
32
33
The command find operates in a similar way on matrices: >> A = [1 3 −3 −5; −1 2 −1 0; 3 −7 2 7]; >> k = find (A >= 2.5) k = 3 4 12 >> A(k) ans = 3 3 7
In this example, find approached the matrix A as a single column vector [which is achieved with the command A(:)] and the returned indices refer to positions in this column vector. The row and column indices of the selected elements are returned by >> [I,J] = find (A >= 2.5) I = 3 1 3 J = 1 2 4 >> [A(I(1),J(1)), A(I(2),J(2)), A(I(3),J(3))] ans = 3 3 7 >> A(sub2ind(size(A),I,J)) ans = 3 3 7
% lists the values
% list the values
or the can be calculated from k by [i,j] = ind2sub(size(A),k). Exercise 5.5. Let A = ceil (5*randn(6,6)). Use both logical indexing and the command find to • find the indices and list all elements of A which are smaller than -3;
• find the indices and list all elements of A which are smaller than 5 and larger than -1;
5.2. Conditional code execution
42
• remove those columns of A which contain at least one 0 element.
5.2 5.2.1
Conditional code execution Using if ...
elseif ...
else ...
end
Selection control structures, if-blocks, are used to decide which instruction to execute next depending whether expression is TRUE or not. The general description of the syntax is presented by the diagrams below, on the left. In the examples on the right, the command disp is used to display specificied messages on the screen. • if ...
end Syntax
if logical_expression statement1 statement2 .... end
• if ...
else ...
if logical_expression block of statements evaluated if TRUE else block of statements evaluated if FALSE end
elseif ...
if (a > 0) b = a; disp ('a is positive'); end
end
Syntax
• if ...
Example
Example if (temperature > 100) disp ('Above boiling.'); toohigh = 1; else disp ('Temperature is OK.'); toohigh = 0; end
end
Syntax if logical_expression1 block of statements evaluated if logical_expression1 is TRUE elseif logical_expression2 block of statements evaluated if logical_expression2 is TRUE end
Example if (price > 100) disp ('too expensive'); elseif (price < 10) disp ('cheap'); end
5.2. Conditional code execution • if ...
elseif ...
43
else ...
end
Syntax
Example
if logical_expression1 block of statements evaluated if logical_expression1 is TRUE elseif logical_expression2 block of statements evaluated if logical_expression2 is TRUE else block of statements evaluated if no other expression is TRUE end
if (height > 190) disp ('very tall'); elseif (height > 170) disp ('tall'); elseif (height < 150) disp ('small'); else disp ('average'); end
Important: at most one block of commands is executed, i.e. the first that matches (if any). Exercise 5.6. For each of the four following fragments of code, predict what results they will produce for the various starting values given on the right. Use Matlab to verify your answers, but be warned that these fragments are not proper Matlab code and therefore might need correction(s) before they work properly. 1.
2.
3.
4.
if n > 1 m = n + 2 else m = n − 2 end
a) n = 7 b) n = 0 c) n = −7
m = ? m = ? m = ?
if s <= 1 t = 2z elseif s < 10 t = 9 − z elseif s < 100 t = sqrt(s) else t = s end
a) b) c) d)
s s s s
= 1 = 7 = 57 = 300
t t t t
= = = =
? ? ? ?
if t >= 24 z = 3t + 1 elseif t < 9 z = tˆ2/3 − 2t else z = −t end
a) b) c) d)
t t t t
= 50 = 19 = −6 = 0
h h h h
= = = =
? ? ? ?
if 0 < x < 7 y = 4x elseif 7 < x < 55 y = −10x else
a) b) c) d)
x x x x
= −1 = 5 = 30 = 56
y y y y
= = = =
? ? ? ?
5.2. Conditional code execution
44
y = 333 end
Exercise 5.7. Create a script that converts the Reynolds number Re of a body in a flow into the resulting drag coefficient C, where 0 Re ≤ 0, Re ∈ (0, 0.1], 24/Re 0.7 (24/Re)(1 + 0.14Re ) Re ∈ (0.1, 1e3], C= 0.43 Re ∈ (1e3, 5e5], 0.19 − 8e4/Re Re > 5e5.
Verify whether your script works correctly by computing various drag coefficients calculated by the script against their values calculated by hand, for e.g. Re = −3 · 103 , 0.01 56, 103 and 3 · 106 . Remember that e.g. 4e5 is Matlab notation of 4 · 105 . Exercise 5.8. Write a script that asks (using input) for an integer and returns whether it can be divided by 2 and/or 3. Consider all possibilities, such as, divisible by both 2 and 3, divisible by 2 but not by 3, etc. Hint: look up the commands mod and rem.
5.2.2
Using switch
Another selection structure is switch, which switches between several cases depending on the value of a variable: Syntax
Example
switch variable case choice1 block of commands1 case {choice2a, choice2b,...} block of commands2 ... otherwise block of commands end
method = 2; switch method case 1 disp('Method is linear.'); case {2,3} disp('Method is cubic.'); otherwise disp('Unknown method.'); end
Important: at most one block of commands is executed, i.e. the first that matches (if any). The variable can be a scalar or a string; a scalar matches if the comparison variable == choice returns 1, a string matches if the comparison strcmp(variable, choice) returns 1. A case can be endowed with multiple matches by using curly brackets, as in the example. The switch construction can be very handy to avoid long if .. elseif ... else ... end constructions. If a case must match many values (say 1 through 100) or a range of values (between 5.5 and 10), an if construction is more appropriate.
5.3. Loops
45
Exercise 5.9. Write a script that asks (using input) the user for the ordinal number of a month and returns the number of days in that month (assuming February has 28 days). Next, modify your script to use the name of a month in stead of the ordinal number.
5.3
Loops
Iteration control structures, loops, are used to repeat a block of commands several times. Two types of loops exist: • The for loop repeats a group of statements a fixed 3 number of times: Syntax
Example
for index = row_vector block of statements end
sumx = 0; for i=1:length(x) sumx = sumx + x(i); end
The row vector is often conveniently created using colon notation, first:step:last. The elements of row vector need not be integers, do not have to be ordered, can be characters and can even be column vectors. Some examples of possible variations: Example 1
Example 2
Example 3
Example 4
for i=1:2:7 ... end
for i=8:-1:3 .... end
for x=0:0.1:1 disp(x^2); end
for x=[25 9 81] disp(sqrt(x)); end
• The while loop evaluates a group of commands as long as an expression holds true: Syntax
Example
while expression statement1 statement2 statement3 ... end
N = 100; iter = 1; msum = 0; while iter <= N msum = msum + iter; iter = iter + 1; end;
Be aware that you can end up with an infinite loop; these can be interrupted with Ctrl–C. As a simple example of how to use the loop construct, execute the following script to draw graphs of f (x) = cos(nx) for n = 1, . . . , 9 ordered in an (3 × 3) array of subplots: 3
The set of values of index is determined when entering the loop and can not be changed within the loop.
5.3. Loops
46
figure hold on x = linspace(0,2*pi); for n=1:9 subplot(3,3,n); y = cos(n*x); plot(x,y); axis tight end
As a second example of for loops, we combine two vectors x and y into a matrix A whose elements are defined as Aij = xi yj . Enter the following commands in a script: n = length(x); m = length(y); for i=1:n for j=1:m A(i,j) = x(i) * y(j); end end
and determine A for x = [1 2 -1 5 -7 2 4] and y = [3 1 -5 7]. Note that A is of size (n × m). The same problem can be solved by using while-loops follows: n = length(x); m = length(y); i = 1; j = 1; while i <= n while j <= m A(i,j) = x(i) * y(j); j = j+1; end i = i+1; end
% initialize i and j
% increment j; it does not happen automatically % increment i
Exercise 5.10. Determine the sum of the first 50 squared numbers with a control loop. Exercise 5.11. Write a script to find the largest value of n for which the sum 12/3 + 22/3 + . . . + n2/3 is less than 1000. Can you also output the value of the sum for that value of n, without evaluating the summation twice and without making use of an array? Exercise 5.12. Use a loop construction to carry out the computations. Write short scripts. 1. Given the vector x = [1 8 3 9 0 1], create a short set of commands that will: • add up the values of the elements (check with sum); • computes the running sum (for element j, the running sum is the sum of the elements from 1 to j; check with cumsum); • computes the sine of the given x-values (should be a vector). 2. Given x = [4 1 6 -1 -2 2] and y = [6 2 -7 1 5 -1], use loops to create matrices whose elements are created according to the following formulas:
5.4. Comments on logical and relational expressions • • • •
47
aij = yi /xj ; bi = xi yi , and sum the elements in btot; cij = xi /(2 + xi + yj ); dij = 1/ max(xi , yj ).
3. Write a script that uses loops to transposes a matrix A. 4. Create an m-by-n array of random numbers (use rand). Move through the array, element by element, and set any value that is less than 0.5 to 0 and any value that is greater than (or equal to) 0.5 to 1. 5. Write a script that will use the random-number generator rand to determine: • the number of random numbers it takes to add up to 10 or more; • the number of random numbers it takes before a number between 0.8 and 0.85 occurs; • the number of random numbers it takes before the mean of those numbers is within 0.01 and 0.5. It will be worthwhile to run your script multiple times, using a loop, because you are dealing with random numbers. Can you predict/explain any of the results?
Exercise 5.13. Write a script that asks for a temperature in centigrade Tc and computes the equivalent temperature in Fahrenheit Tf , using the formula Tf = 9/5Tc + 32. The script should keep running until no number is provided to convert. The functions input and isempty (use help to learn more) should be useful here. Exercise 5.14. Matlab is flexible in allowing non-integer indices in for loops. This is not without risk, however. Try what happens when you run the following code: for i = 0 : 1/7 : 1 j(7*i) = i end
Can you explain why this fails, and suggest (trivial) remedies?
5.4
Comments on logical and relational expressions
As relational and logical expressions get increasingly more complex, one can easily run into situations where the evaluation of the second part of an expression becomes conditional to the result of the first part of that expression. Consider the following example to determine whether a matrix A is invertible, which requires the matrix to be square and have a non-zero determinant: s = size(A) invble = ( s(1) == s(2) ) & ( det(A) ∼= 0 )
This code works fine for square matrices, but for non-square matrices terminates with the error message ‘Error using det, matrix must be square.’ What happens is that the two relational
5.4. Comments on logical and relational expressions
48
operations on the second line are both evaluated, followed by a logical operation combining the partial results. Hence, the determinant is evaluated even if the negative result of the ‘preceding’ size check already establishes that the matrix is non-invertible. The solution is know as ‘shortcircuiting’, forcing the code to evaluate the second condition only when its outcome is relevant for the overall result, that is, when the first part of an AND is true or when the first part of an OR is false. To force Matlab to use short-circuiting, the logical bitwise & or | operators must be doubled to && or ||,4 as in invble = ( s(1) == s(2) ) && ( det(A) ∼= 0 )
Matlab defaults to short-circuiting in if and while statements. Important: The fact that computers make use of finite-precision arithmetic means that you should be careful when comparing two floating-point numbers. The code block in the following if statement will only be executed if x and y are identical down to the last digit, if (x == y) block of statements end
This construction is fine if x and y are integers or have both been assigned the same value (y = x), but if x and y are the results of two distinct calculations there is a good chance that they are not completely identical, even if they should be identical following an analytic calculation. In stead of the above construction, one is advised to use if (abs (x − y) < tolerance) block of statements end
% e.g. tolerance = 1e−10
Exercise 5.15. Consider the following example: max iter = 50; tolerance = 1e−4; iter = 0; xold = 0.1; x = 1; while (abs (x − xold) > tolerance) & (iter < max iter) xold = x; x = cos(xold); iter = iter + 1; end
This short program iteratively solves the equation cos(x) = x, with x holding the best approximation. Note that the while-loop is repeated as long as both conditions are true: when either condition is met, the loop aborts. Run the script for various values of the tolerance parameter, e.g.: 10−2, 10−4 , 10−6 10−8 , 10−10 . Compare the final values of x and cos(x), by using format long and by calculating their difference. How does the number of iterations, iter, vary with the requested tolerance? 4
Note that & and | will work on arrays, returning an array of logicals, while && and || will only work on scalars, returning a single logical.
5.4. Comments on logical and relational expressions
49
Figure 5.1: Sectioning of a circle into triangles to approximate π. (Copied from the BEAM-B handout.) Exercise 5.16. Modify the above script by replacing the while-loop condition with while (abs (x − xold) > tolerance) | (iter < max iter)
Try to understand the difference between the two codes, and verify your expectations by running the second script. What happens to iter? Exercise 5.17. One can approximate 2π, the circumference of a unit circle (radius = 1), as follows: Section the circle into triangles, as in figure 5.1. Starting at n = 1 with four identical triangles running from (0, 0) to (±1, 0) and (0, ±1), the √ lengths sn of the bases of these triangles (i.e. the sides facing the circumference) equals s1 = 2. As a first approximation for the circumference of the circle, one obtains 4s1 ≈ 5.66. Next, the number of triangles is doubled. Then, length a equals half the length sn . Lengths b and c can be computed – without using goniometric functions – so the length of the new bases, sn+1 , is also known. An improved approximation for the circumference of the circle is readily obtained. Write a script to evaluate the approximate circumferences while the number of triangles is doubled at least 20 times.
Chapter 6 Functions
Matlab M-files were introduced in chapter 4 to collect commands in scripts. In this chapter m-files are used to define functions.
6.1
Function m-file
Function m-files are true subprograms, taking input arguments and/or returning output parameters. They can call other functions as well. Variables defined and used inside a function, different from the input/output arguments, are not visible to other functions nor to the command environment. The general syntax of a function is: function [outputArgs] = function name (inputArgs) block of statements end % or: return
outputArgs are enclosed in [ ]: – a comma-separated list of variable names; – the brackets [ ] are optional when only one argument is returned; – functions without outputArgs are legal.1 inputArgs are enclosed in ( ): – a comma-separated list of variable names; – functions without inputArgs are legal, in which case the brackets ( ) are optional. Matlab provides a structure for creating your own functions. The first line of the file should contain the definition of the new function, also called the header. Next follows a continuous sequence of comment lines, to explain what the function does, especially when this is not trivial. 1
In other programming languages, functions without output arguments are called procedures.
– 50 –
6.1. Function m-file
51
You are advised to also discuss the expected input parameters and the format of the output, to make life easier on the user (which includes you in a couple of months). These comment lines, up to the first non-comment line, will be displayed in response to the help command. The remainder of the function, the body, contains the main code of the function. Function m-files terminate execution and return to their invoker when they reach the end of the function or, alternatively, when the command return is encountered. As an example, the function average is defined as follows: output argument the first line must be the function definition comment
function name
input argument
function avr = average (x) %AVERAGE computes the average value of a vector x % and returns it in avr % Notes: an example of a function
function body
n = length(x); avr = sum(x)/n; return;
a blank line within the comment; Notes information will NOT appear when you ask: help average
Important: Matlab identifies functions in m-files by the name of the m-file; the name in the header is ignored. It is good practice, however, to keep these two names identical. Exercise 6.1. Create the function average and store it on disk as average.m. Test whether average.m functions properly by typing avr1 = average(1:10); What message appears when you call help average? Here is an another example of a function: function [avr,sd] = stat(x) %STAT Simple statistics. % Computes the average value and the standard deviation of a vector x. n = length(x); avr = sum(x)/n; sd = sqrt(sum((x − avr).ˆ2)/n); return; % or: end
Try invoking the above function by issuing the commands v = rand(10,1); stat(v) j = stat(v); [j,k] = stat(v)
Note that the first two invocations return a single value, i.e. the average, which is displayed on screen and stored in j, respectively. The last invocation returns two values, the average is stored in j and the standard deviation is stored in k. In sending and receiving information between an invoker and a function, the names of the variables are unimportant – these are ‘private’ to the sender and receiver, see section 6.2 – but it is the order of the variables that determines the communication of values: j receives the value of avr and k receives the value of sd. If one is interested in the second, but not the first, returned argument: [~,k] = stat(v). Warning: The functions mean and std already exist in Matlab. If the name of a function is also used as a variable name, it becomes impossible to access that function. Many other easily
6.1. Function m-file
52
appealing names, such as sum and prod, are also reserved by Matlab functions, so be careful when choosing your names (see section 9.3). The return statement can be used to force an early return. An example: function d = determinant(A) %DETERMINANT Computes the determinant of a matrix A [m,n] = size(A); if (m ∼= n) disp ('Error. Matrix should be square.'); return; % exits the function immediately else d = det(A); % standard Matlab function end return;
The use of the return command in combination with a check on the number of input arguments is given in the function checkarg in section 6.5. In controlling the proper use of parameters, the function error may prove useful. It displays an error message, aborts function execution and returns to the command environment. Here is an example: if (a >= 1) error ('a must be smaller than 1'); end
Exercise 6.2. Change some scripts that you created into functions, e.g. create the function drag to computing the drag coefficient (see section 5.2), or the function solve cos (see section 5.4) or the function cubic roots (see section 4). Exercise 6.3. Write the function [elems, mns] = nonzero(A) that takes as the input argument a matrix A and returns all nonzero elements of A in the column vector elems. The output parameter mns holds values of the means of all columns of A. Exercise 6.4. Write the function [meanrow, meancol] = allmeans(A) that takes as the input argument a matrix A and returns the means of all its rows and columns respectively. Exercise 6.5. Create the function [A,B,C] = sides(a,b,c) that takes three positive numbers a, b and c. If they are sides of a triangle, then the function returns its angles A, B and C, measured in degrees. Display an error when necessary. Exercise 6.6. p The area of a triangle with sides of length a, b and c is given by: A = s (s − a) (s − b) (s − c), where s = (a + b + c)/2. Write a function that accepts a, b and c as input and returns the area A as output. Note that the sides should be non-negative and should obey the triangle inequality. Make use of the error command to report violations.
6.2. Local and global variables
53
Exercise 6.7. Create the function randint that generates random matrices of integer numbers (use the command rand). The integers should come from the interval [a, b]. Exercise in documenting the function. Use the following function header: function r = randint(m,n,a,b)
% an (m x n) matrix
If this is too difficult, start with a fixed interval, e.g. [a, b] = [0, 5] (and remove a and b from the function definition), before attempting the arbitrary interval.
6.2
Local and global variables
Each m-file function has access to a part of memory separate from Matlab’s workspace. This is called the function workspace. This means that each m-file function has its own local variables, which are separate from those of other functions and from the workspace. To understand this better, analyze the following diagram: Matlab workspace >> a = -1; >> b = 20; >> c = 5; >> i = 12; >> d = myfun (a,b)
(a, b) −→ (x, y) d ←− z
myfun.m function z = myfun(x,y) w = x - y i = 25 z = x + cos(w); return;
In the Matlab workspace, only the variables a, b, c, d and i are available. The variables w, x, y, z and i are available only in the function myfun. Because the variables are local, it is impossible for commands in the workspace to alter the values of variables in the function (with the exception of the values being passed as arguments at the invocation) and likewise it is impossible for commands in the function to alter the values of variables in the workspace (with the exception of the values being returned when the function finishes). We can therefore use the same variable name(s) multiple times, like i in the above example, without the danger that changing the value of i in the function has (potentially disastrous) consequences for the value of i in the workspace, and vice versa. Each function has its private set of variables. The arrows in the center highlight the sending and receiving of values between the workspace and the function, with the value of a transferred to x and the value of b transferred to y; the same order-based protocol also applies for function output and for communication between functions. It can sometimes be useful for several functions and/or the workspace to have access to the same variable. This can be realised by declaring a particular variable as global in the functions (and the workspace) that require access to this variable, see help global. Note that it is very easy to end up with serious errors. The values of the variables within a functions are typically lost when the function terminates. Variables that are to be reused in a later invocation of a function must be declared persistent.
6.3. Subfunctions
6.3
54
Subfunctions
A function m-file may contain multiple functions. The function appearing first in the m-file shares the file name, as mentioned before. Subsequent functions are subfunctions and can be called from the primary function only: they can not be accessed from outside the file in which they are defined, neither from the Command Window nor via any other m-file. A subfunction is created by defining a new function with the function statement after the body of the preceding function. The use of subfunctions is recommended to keep the main function readable when it becomes too long and/or too complicated. In the below example, average is a subfunction within the file stat.m: function [a,sd] = stat(x) %STAT Simple statistics. % Computes the average value and the standard deviation of a vector x. n = length(x); a = average(x,n); sd = sqrt(sum((x − avr).ˆ2)/n); return; function a = average (x,n) %AVERAGE subfunction a = sum(x)/n; return;
Frequently-called small functions are best included as subfunctions, so they reside in memory simultaneously with the invoker. This enables quick access to the (sub)function, and avoids Matlab repeatedly scanning your disk for the function m-file and repeatedly loading the file into memory. Subfunctions can also be appended to script files. Exercise 6.8. Modify the function stat presented above by using the subfunction average for the computation of variable sd as well.
6.4
Nested functions
Related to sub-functions are the ‘nested’ functions, i.e. functions that are fully contained within another function. Try for example function parent x = 4 y = 3 disp('In parent') nested(y) x,y function nested(z) disp('In nested') x = x + z; end % nested end % parent
6.5. Special function variables
55
The main difference between nested and sub-functions is that nested functions can see the data of the parent function(s). Therefore the code above is perfectly valid and the function nested changes the value of x in parent. Note that the variable z is local to nested, and that the commands in nested are only executed when the function is actually called.
6.5
Special function variables
Every function has two internal variables: nargin - the number of function input arguments that were used when call the function and nargout - the number of output arguments expected by the call. Analyze the following function: function [out1,out2] = checkarg (in1,in2,in3) %CHECKARG Demo on using the nargin and nargout variables. if (nargin == 0) disp('no input arguments'); return; elseif (nargin == 1) s = in1; p = in1; disp('1 input argument'); elseif (nargin == 2) s = in1+in2; p = in1*in2; disp('2 input arguments'); elseif (nargin == 3) s = in1+in2+in3; p = in1*in2*in3; disp('3 input arguments'); else error('Too many inputs.'); end if (nargout == 0) return; elseif (nargout == 1) out1 = s; else out1 = s; out2 = p; end
The cell arrays (see section 7) varargin and varargout allow an indefinite number of input and output arguments to a function. Exercise 6.9. Construct the function checkarg and call it with various numbers of input and output arguments to try and understand its behavior. For example: >> >> >> >>
checkarg s = checkarg(−6) s = checkarg(23,7) [s,p] = checkarg(3,4,5)
6.6. Indirect function evaluation
56 optional
6.6
Indirect function evaluation
Using indirect function evaluation makes programming even more general, since functions can become input arguments. The Matlab command here is feval, an abbreviation of function evaluation. The feval command allows execution of a function specified by a string. The general definition is as follows: [y1,..,yn] = feval (F,x1,...,xn),
where F is a name of a function, x1,...,xn are input arguments and y1,...,yn are output parameters. Consider the example: >> x = pi; y = cos(x); >> z = feval('cos',x);
The last command is also equivalent to the following two expressions: >> F = 'cos'; >> z = feval(F,x)
Indirect function evaluation is a nice tool to build a program with a function given as an argument. Exercise 6.10. Create the function funplot and try to understand how it works: function funplot (F, xstart, xend, col); %FUNPLOT makes a plot of the function F at the interval [xstart, xend]. % The plot should be made in one of the standard Matlab colors, so % 'col' is one of the following value: 'b','k','m','g','w','y' or 'r'. % default values: % [xstart,xend] = [0,10] % col = 'b' % Note: illustrates the use of feval command if (nargin == 0) error ('No function is provided.'); end if (nargin < 2) xstart = 0; xend = 10; end if (nargin == 2) error ('Wrong number of arguments. You should provide xstart and xend.'); end if (nargin < 4) col = 'b'; end if (xstart == xend), error ('The [xstart, xend] should be a non−zero range.');
6.7. Scripts versus functions
57
elseif (xstart > xend), exchange = xend; xend = xstart; xstart = exchange; end switch col case {'b','k','m','g','w','y','r'} ; otherwise error ('Wrong col value provided.') end
% do nothing; the right color choice
x = linspace(xstart, xend); y = feval(F,x); plot (x,y,col); description = ['Plot of ', F]; title (description); return;
Note the use of comments, the nargin variable and the switch-construction. Call funplot for different built-in functions, like sin, exp, etc. Test it for your own functions as well: write for example a function myfun that computes sin(x cos(x)) or log( |x sin(x)| ). Explain why it would be wrong to use the fragment given below instead of its equivalent part in funplot. if nargin < 2 xstart = 0; xend = 10; elseif nargin < 3 error ('Wrong number of arguments. You should provide xstart and xend.'); elseif nargin < 4 col = 'b'; end
We will encounter more versatile forms of indirect function evaluation in section 12.2.1 and 12.3.2, where an inline function and a function handle @, respectively, are passed as argument to a function. end optional
6.7
Scripts versus functions
The most important difference between a script and a function is that all parameters and variables in the script are externally accessible (i.e. in the workspace), while function variables are not easily accessed. Therefore, a script is a good tool for documenting work, designing experiments and testing. In general, functions are created to solve a given sub-problem for arbitrary parameters; in many cases functions are operated as black boxes, e.g. the in-built functions of Matlab (though it is highly recommended to test them before you use them, to make sure that you understand their functioning, the structure of the input and output, and whether they are suitable for your sub-problem). Use a script to run functions for the specific parameters required by the problem at hand.
6.8. Exercises
6.8
58
Exercises
Exercise 6.11. Create a Matlab function to evaluate the expression 1 n f (n) = 1 + n as a function of n. Next check the outcome of this expression for increasing n. Can you verify that lim f (n) = e? n→∞
Exercise 6.12. Create the function binom that computes the value of the binomial symbol nk . Make the function header: function b = binom (n,k). Note that in order to write this function, you will have to create the factorial function, which computes the value of n! = 1 ∗ 2 ∗ ... ∗ n. This may become a separate function (enclosed in a new file) or a subfunction in the binom.m file. Try to implement both cases if you got acquainted with the notion of a subfunction. Having created the binom function, write a script that displays on screen all the binomial symbols for n = 8 and k = 1, 2, ..., 8 or write a script that displays on screen the following ’triangle’ (use the fprintf command; try help fprintf. Note fprintf is a c-command, which is in the header cstdio (with the same syntax), but C++: streams are much better for dealing with input/output, so its use is not recommended in C++:. 1 1 2 2 2 1 3 3 3 1 2 3 4 4 4 4 1
2
3
4
Exercise 6.13. Solve the following exercises by using either a script or a function. The nature of the input/output and display options is left to you. Problems are presented with the increasing difficulty; start simple and add complexity. If possible, try to solve all of them. 1. Write a function that computes the cumulative product of a vector elements. Q The cumulative product up to the j-th element of the vector x is defined by Cj = jk=1 xk for j = 1 : length(x). Check your results with the built-in function cumprod. 2. Write P a function P m = wmean (x,w) to compute the weighted arithmetic mean, defined as ( ni=1 wi xi )/( ni=1 wi ), given the vector x and a vector of nonnegative weights w. Include error messages to terminate execution of the function in case: – x and w are of different lengths, – any element of w is negative, – the sum of all weights is equal to zero. 3. What is the largest value of n for which the sum 12 + 22 + 32 + . . . + n2 is less than 100?
6.8. Exercises
59
4. Compute the value of π using the series: ∞
1 π2 − 8 X = 2 16 (2n − 1) (2n + 1)2 n=1 How many terms are needed to obtain an accuracy of 10−12 ? How accurately does the sum of 100 terms approach π? 5. Write a program that approximates π by computing the sum: ∞
π X (−1)n = 4 n=0 2n + 1 The more terms are included in the summation, the higher the accuracy (although this is not an efficient formula, since you add and subtract numbers). How many terms are needed to approximate π with 5 decimals? Use the sum to approximate π using 10, 100, 103 , 104 , 105 and 016 terms. For each of these numbers, compute the approximation error. Plot the error as a function of the number of terms used in the summation. 6. The Fibonacci numbers are computed with the following relation: Fn = Fn−1 + Fn−2 ,
with
F0 = F1 = 1.
– Compute the first 10 Fibonacci numbers. – For the first 50 Fibonacci numbers, compute√the ratio Fn /Fn−1 . It is claimed that this ratio approaches the golden mean, (1 + 5)/2. What do your results show? 7. Consider the problem of computing the n-th Fibonacci number. Find three different ways to implement this and construct three different functions, say fib1, fib2 and fib3. Measure the execution time of all functions (use the commands tic and toc) for, say, n = 20, 40 and 100. 8. The Legendre polynomials Pn (x) are defined by the recurrence relation: (n + 1) Pn+1 (x) − (2n + 1) x Pn (x) + n Pn−1 (x) = 0 with P0 (x) = 1, P1 (x) = x and P2 (x) = (3x2 − 1)/2. Compute the next three Legendre polynomials and plot all six over the interval [−1, 1]. 9. Write a script that asks for an integer n (or a function that has n as the input argument) and then runs the following algorithm: While the value of n is greater than 1, replace an even n with (n/2) and an odd n with (3n + 1). Count the number of values in the sequence that results. Example: For n = 10, the sequence reads as 5, 16, 8, 4, 2, 1 and the number of values is 6. For n = 10, the sequence counds 17 elements. Make a plot of the length of the sequence as a function of n for n = 2 to 30. Is there any pattern? Try larger numbers to see whether the pattern persists. Are there n’s for which the sequence does not terminate? 10. Provide all prime numbers smaller then a given N .
Chapter 7 Cell arrays and structures
7.1
Cell arrays
Cell arrays are arrays whose elements are cells. Each cell can contain any data, including numeric arrays, strings, cell arrays etc. For instance, one cell can contain a string, another a numeric array etc. Below, is a schematic representation of an exemplar cell array:
cell 1,1 3 1 -7 7 2 4 0 -1 6 7 3 7 cell 2,1
cell 1,2
cell 1,3
John Smith 1 + 3i
35 5900 6000 6100
cell 2,3
cell 2,2 ’Hi’
[7,7]
’this is a text’ -1 0 0 -1
’Bye’
’Living’ ’implies effort’
Cell arrays can be built up by assigning data to each cell. The cell contents are accessed by brackets {}. For example: >> >> >> >> >> >> >>
A(1,1) A(2,1) B(1,1) A{1,2} C(1,1) A(2,2) A
= = = = = =
{[3 1 −7;7 2 4;0 −1 6;7 3 7]}; {'this is a text'}; {'John Smith'}; B(2,1) = {35}; B(3,1) = {[5900 6000 6100]} B; % cell array B becomes one of the cells of A {'Hi'}; C(2,1) = {[−1 0;0 −1]}; C(1,2) = {[7,7]}; C(2,2) = {'Bye'}; {C}; % cell array C becomes one of the cells of A % A represents now the first 2 columns of the exemplar % cell array
– 60 –
7.2. Structures
61
A = [4x3 double] {3x1 cell} 'this is a text' {2x2 cell} >> A(2,2) % access the cell but not its contents ans = {2x2 cell} >> A{2,2} % use {} to display the contents ans = 'Hi' [1x2 double] [2x2 double] 'Bye' >> A{2,2}{2,1} % take the (2,1) element of the cell A{2,2} ans = −1 0 0 −1
There are also two useful functions with meaningful names: celldisp and cellplot. Use help to learn more. The common application of cell arrays is the creation of text arrays. Consider the following example: >> M = {'January';'February';'March';'April';'May';'June';'July';'August'; 'September';'October';'November';'December'}; >> fprintf ('It is %s.\n', M{9}); It is September.
Exercise 7.1. Exercise with the concept of a cell array, first by typing the examples presented above. Next, create a cell array W with the names of week days, and using the command fprintf, display on screen the current date with the day of the week. The goal of this exercise is also to use fprintf with a format for a day name and a date, in the spirit of the above example.
7.2
Structures
Structures are Matlab arrays with data objects composed of fields and are very similar to classes in c++, see section 22. Each field contains one item of information. For example, one field might include a string representing a name, another a scalar representing age or an array of the last few salaries. Structures are especially useful for creating and handling a database. One of the possible ways to create a structure is by assigning data to individual fields. Imagine that you want to construct a database with some information on workers of a company: >> >> >> >>
worker.name = 'John Smith'; worker.age = 35; worker.salary = [5900, 6000, 6100]; worker = name: 'John Smith' age: 35 salary: [5900 6000 6100]
In this way, a 1×1 structure array worker with three fields: name, age and salary is constructed. To expand the structure, add a subscript after the structure name:
7.2. Structures
62
>> worker(2).name = 'Linda Murphy'; >> worker(2).age = 41; >> worker(2).salary = [7301, 7301]; >> worker 1x2 struct array with fields: name age salary
% after this, a 2nd subarray is created % field sizes do not need to match!
Since this structure has now the size of 1 × 2, Matlab does not display the contents of all fields. The data are now organized as follows:
worker array
worker(1)
worker(2)
.name
John Smith
.name
Linda Murphy
.age
35
.age
41
.salary
5900, 6000, 6100
.salary
7301, 7301
Structures can also be build by using the struct function. For example: >> employee=struct( 'name','John Smith','age',35,'salary',[5900, 6000, 6100]);
To create an empty structure with fields field1, field2 s = struct('field1', {}, 'field2', {})
To create an empty structure with no fields struct([])
To access an entire field, include a field name after a period. To access a subarray, follow the standard way of using subscripts: >> worker(1).age 35 >> worker(2).salary(2) 7301 >> worker(2) name: 'Linda Murphy' age: 41 salary: [7301 7301]
An alternative way is to use the getfield function:
7.3. Object handles and the internal set and get functions
63
>> getfield(worker,{2},'salary') 7301 7301
There exists also a function setfield, which assigns values to a given field. New fields can be added or deleted from every structure. To delete a field, use the command rmfield. Analyze the following example: worker2 = worker; worker2 = rmfield (worker, 'age'); worker2(2).street = 'Bakerstreet 5'; worker2(2) name: 'Linda Murphy' salary: [7301 7301] street: 'Bakerstreet 5' >> worker2(1) name: 'John Smith' salary: [5900 6000 6100] % in all other substructures address field is empty street: [] % you should assign new values for each substructure >> >> >> >>
Operating on fields and field elements is done in the same way as on any other array. Consider the following example, where the average salary for each worker is computed. avr salary(1) = mean (worker(1).salary); avr salary(2) = mean (worker(2).salary);
Remark: structures as a concept are common organisations of data in other programming languages. They are created in different ways, but the intention remains the same. Exercise 7.2. Construct a structure friend, with the following fields: name, address, age, birthday. Insert a few friends with related information. Remove e.g. the field age and add the field phone. Concerning the use of lists and parentheses in Matlab, please see help lists and help paren. General remark: Classes and objects allow for adding new data types and new operations to Matlab. For instance, the class of a variable describes the structure of the variables and the operations permitted as well as functions to be used. An object is an instance of a particular classs. The use of classes and objects is the base of object-oriented programming, which is also possible in Matlab.
7.3
Object handles and the internal set and get functions
Everything MATLAB creates is an object, with children and parents very similar to OOP in C++. Understanding how this works allows very fine control over the internal working of MATALB. Everything in MATLAB has a unique handle (a way of identifying it). A simple handle example would be a figure handle, >> a=figure; a=
7.3. Object handles and the internal set and get functions
64
1
The value assigned to a is the handle of the new figure. Note, figure are always assigned integers, starting at 1 for the first figure you create. Now you can view all the properties of this figure using the get command, which is the internal version of getfield. The same information is also obtained by double clicking on f in the workspace. >> get(a) Alphamap = [ (1 by 64) double array] CloseRequestFcn = closereq Color = [0.8 0.8 0.8] Colormap = [ (64 by 3) double array] CurrentAxes = [] CurrentCharacter = CurrentObject = [] CurrentPoint = [0 0] DockControls = on DoubleBuffer = on FileName = FixedColors = [ (3 by 3) double array] IntegerHandle = on InvertHardcopy = on KeyPressFcn = KeyReleaseFcn = MenuBar = figure MinColormap = [64] Name = NextPlot = add NumberTitle = on PaperUnits = inches PaperOrientation = portrait PaperPosition = [0.25 2.5 8 6] PaperPositionMode = manual PaperSize = [8.5 11] PaperType = usletter Pointer = arrow PointerShapeCData = [ (16 by 16) double array] PointerShapeHotSpot = [1 1] Position = [360 280 560 420] Renderer = None RendererMode = auto Resize = on ResizeFcn = SelectionType = normal ToolBar = auto Units = pixels WindowButtonDownFcn = WindowButtonMotionFcn = WindowButtonUpFcn = WindowScrollWheelFcn = WindowStyle = normal XDisplay = localhost:10.0 XVisual = [ (1 by 59) char array] XVisualMode = auto BeingDeleted = off ButtonDownFcn = Children = [] Clipping = on CreateFcn =
7.3. Object handles and the internal set and get functions
65
DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [0] Selected = off SelectionHighlight = on Tag = Type = figure UIContextMenu = [] UserData = [] Visible = on
These are all the properties of a figure in MATLAB, and manipulating these allows you too fine tune many things from within your script files. This brings us to the set command which allows us to set properties of anything internal in MATLAB (that does not have to be a figure). For example >> set(a,'name','MyFigure'); >> a.Name = 'MyFigure';
gives your figure the name ‘MyFigure’. The second way of assigning a value to a built-in handle, which unlike the first is case sensitive, was introduced recently to conform with the accessing of structures. Now lets plot something on out figure. Type the following >> figure(a); >> b = ezplot('sin'); b= 317.0021
The first line makes sure that the figure with handle a is the active figure, the second command plots the sin function in this figure. This time the returned value is 317.0021 and the handle is assigned to the variable b. In recent versions of Matlab, rather than a ‘random’ numerical value you receive some more informative information, >> figure(a); >> b = ezplot('sin') b = Line with properties: Color: LineStyle: LineWidth: Marker: MarkerSize: MarkerFaceColor: XData: YData: ZData:
[0 0.4470 0.7410] '−' 0.5000 'none' 6 'none' [1 4 3 4 double] [1 4 3 4 double] [1 0 double]
Show all properties
7.3. Object handles and the internal set and get functions
66
You can now make the line of this plot thicker via the either command >> set(b,'LineWidth',10); >> b.LineWidth = 10;
7.3.1
Parents and children
MATLAB has a hierarchal structure: a figure can have many axes and each axis can have many plots. The relationship between figure, axes and plots is maintained by the Parent and Children fields. This is illustrated by the following example. fig1 = figure; plot1 = ezplot('sin'); hold on; plot2 = ezplot('cos');
The hold on makes sure the plots are on the same axes. Now notice that get(fig1,’Children’) returns the same as get(plot1,’Parent’) and get(plot2,’Parent’): all three yield the handle of the axes in the figure. Now get a hold on this axes handle using one out of three options, e.g. axes1 = get(fig1,’Children’) or axes1 = plot2.Parent. Notice that axes1 has a number of fields specifying the properties of the axes, as well as two children referring to the two plots on these axes. Try what happens when you type >> >> >> >>
axes1.YLabel.String='Sin and Cos'; axes1.Children(1).LineWidth = 5; fig1.Children.Children(2).LineWidth = 5; axes1.Parent.Name = 'EZplot';
This has been a very superficial overview of the power of the set and get commands, but once you understand the basics it is a simple job to manipulate these figure properties to give you very fine control. Exercise 7.3. Write a function which takes a figure handles and will change the line width of all plots on the figure to 10. Hint, you need to get all axes first and then all plots on each of the found axes. Exercise 7.4. Check the default value for the following figure properties • PaperUnits • PaperType • Units
7.3. Object handles and the internal set and get functions
67
Exercise 7.5. The default for Matlab is American units. Write a script file that takes a figure file and changes all the setting to metric standards, that is, • Paper Units to centimeters • Paper type to A4 • Units to centimeters
Exercise 7.6. Write a function that takes an initially unknown list of figure handles and places then together on one subplot matching as closely as possible the aspect of 3 plots across to 2 plot down.
Chapter 8 File input/output operations
The easiest way to write data to a formatted file is the save -ascii command described in chapter 1. It creates a file containing the data, but you have no control over the format nor can you add a header clarifying the content of the file. To read a file created this way, simply type load(’filename.txt’). In this section we will discuss commands that provide much more control over writing to reading from file. Matlab’s file input and output (I/O) functions read and write arbitrary binary and formatted text files. This enables you to read data collected in other formats and to save data for other programs as well. Before reading or writing a file, you must open it with the fopen command: >> fid = fopen (file name, permission);
The permission string specifies the type of access you want to have: • • • •
‘r’ - for reading only ‘w’ - for writing only ‘a’ - for appending only ‘r+’ - both for reading and writing
Here is an example: >> fid = fopen ('results.txt','w')
% tries to open the file results.txt % for writing
The fopen statement returns an integer file identifier, which acts like a handle to the file: it will be used, rather than the file name, to refer to a specific file for input and output. When fopen fails, e.g. when trying to open a non-existing file, the file identifier becomes −1. It is possible to get a more detailed error message, by storing the second (optional) output argument.
– 68 –
8.1. Formatted files
69
It is good practice to test the file identifier every time you open a file. The example below keeps asking the user for a file name, until the name of a readable file is given: fid = 0; while fid < 1 fname = input ('Open file: ', 's'); [fid, message] = fopen (fname, 'r'); if (fid == −1) disp (message); end end
Exercise 8.1. Create a script with the above code and check its behavior when you give a name of a nonexisting file (e.g. noname.txt) and that of an existing readable file (e.g. one of your functions).
When you finish working on a file, use fclose to close it. Matlab automatically closes all open files when you exit it. However, you should close your files when you finish using them: fid = fopen ('results.txt', 'w'); ... fclose(fid);
as this, among others, informs the operating system that the file is again available to other users. Type also help fileformats to find out which file formats are readable in Matlab.
8.1
Formatted files
Files using the American Standard Code for Information Interchange (ASCII) contain text and numbers in a human-readable format, hence they are referred to as ‘formatted’. This makes them user-friendly, but also bulky if you want to store floats up to machine precision. The more compact ‘binary files’ are preferred when storing large amounts of data, but they are not easily read (try reading a Matlab figure file) and are therefore called ‘unformatted’. We will here stick with formatted files, and briefly discuss one type of binary files (for Excel) in section 8.2.
8.1.1
Writing formatted files
For more control over the output file we use fprintf. This command converts data to character strings and displays the resulting string on screen or writes it to a file. The general syntax is: fprintf (fid,format,a,...)
For a more detailed description, consult Matlab’s ‘Reference page for fprintf’ (the link can be found at the bottom of help fprinf). Consider the following example:
8.1. Formatted files >> >> >> >> >> >>
70
x = 0:0.1:1; y = [x; exp(x)]; fid = fopen ('exptab.txt','w'); fprintf(fid, 'Exponential function\n'); fprintf(fid, '%6.2f %12.8f\n',y); fclose(fid);
Exercise 8.2. Prepare a script that creates the sintab.txt file containing a short table of the sinus function.
8.1.2
Reading formatted files
Reading a formatted data file requires no more effort than >> fid = fopen('filename.txt','r'); >> C = textscan(fid, '%s', 'delimiter', '\n'); >> fclose(fid);
where ’%s’ tells Matlab to interpret the file as a collection of strings, and ’delimiter’,’\ n’ specifies that all information on the same line belongs together. The entire file is now loaded into the cell array C, with the fifth line of the file stored as a string in C{1}{5}. This string is readily converted into numbers using str2num. Note that this command can also be used to distinguish between the (text-based) header lines and (number-based) data lines. Exercise 8.3. Extend the above script to read your sintab.txt file and plot the data. When the fixed format of the data file is known, one may also use >> >> >> >>
fid = fopen('filename.txt','r'); A = textscan(fid, '%s', 1, 'delimiter', '\n'); B = textscan(fid, '%6.2f %12.8f', 'delimiter', '\n'); fclose(fid);
% 1 header line % data lines
The data are now contained, as numbers, in the cell array B. Exercise 8.4. Extend the above script to read your sintab.txt file and plot the data. Exercise 8.5. Create a script that reads your sintab.txt file and at the end of that file adds, after a blank line, a matching series of cosine values. Note that you should open the file both for reading and writing. The older Matlab commands to read files, like are fscanf, fgetl and dlmread, are less userfriendly.
8.2. Excel files
8.2
71
Excel files
Using xlswrite and xlsread you can use Matlab to exchange data with Microsoft Excel via a spreadsheet file (.xls) This example writes the following mixed text and numeric data to file, >> d = {'Time', 'Temp'; 12 98; 13 99; 14 97}; >> xlswrite('tempdata.xls', d, 'Temperatures', 'E1')
Exercise 8.6. Run the above script and open the resulting file in Excel. Exercise 8.7. Prepare a script that creates the costab.xls file containing a short table of the cosine function.
Exercise 8.8. Create a table of data in Excel, save the data as an xls-file, and import the data in Matlab.
Chapter 9 Writing and debugging Matlab programs
The recommendations in this section are general for programming in any language. Learning them now will turn out to be beneficial in the future and while learning ‘real’ programming languages like C/C++, where structured programming is indispensable.
9.1
Structural programming
Never write all code at once; program in small steps, and make sure that each of these small steps works as expected, before proceeding to the next one. Each step should be devoted to only one task. Do not attempt to solve too many tasks in one module, because you may easily end up with a mess. This is called a structured or modular way of programming. Formally, modularity is the hierarchical organisation of a system or a task into self-contained subtasks and subsystems, each having a prescribed input-output communication. It is an essential feature of a well designed program. The benefits of structural programming are: easier error detection and correction, modifiability, extensibility and portability. A general approach to program development: 1. Specification. Read and understand the problem. The computer can not do anything itself: you have to tell it how to operate. Before using the computer, some level of preparation and thought is required. Some basic questions to be asked are: • What are the parameters/inputs for this problem? • What are the results/outputs for this problem? • What form should the inputs/outputs be provided in? • What sort of algorithms is needed to find the outputs from the inputs? 2. Design. Split your problem into a number of smaller and easier tasks. Decide how to implement
– 72 –
9.1. Structural programming
73
them. Start with a schematic implementation to solve your problem, e.g. create function headers or script descriptions (and decide about the input and output arguments). To do this, you may use, for example, a top-down approach. You start at the most general level, where your first functions are defined. Each function may be again composed of a number of functions (or subfunctions). While ‘going down’ your functions become more precise and more detailed. As an example, imagine that you have to compare the results of a given problem for two different datasets, stored in the files data1.dat and data2.dat. Schematically, such a top-down approach could be designed as: • At the top (the most general) level, a script solve it is created: d1 = read data( 'data1.dat' ); d2 = read data( 'data2.dat' ); [res1, err1] = solve problem( d1 ); [res2, err2] = solve problem( d2 ); compare results( res1, res2, err1, err2 );
• At the second level one defines the functions called at the first level, read data, solve problem and compare results. Each of them is contained in a separate mfile: ◦
function d = read data( fname ) % Here should be some description. % fid = fopen( fname,'w' ); .... % check whether the file fname exists fclose( fid1 ); d = ... % read the data from file return;
◦
function [res, err] = solve problem( d ) % Here should be some (possibly detailed) description. % .... res = ... % the data d is used to compute res err = compute error( res ); return;
◦
function compare results( res1, res2, err1, err2 ) % Some description. tol = 1e−6; % always place 'constants' at the top .... if abs( err1 − err2 ) > tol fprintf('The difference is significant.') else fprintf('The difference is NOT significant.') end; return;
• The third level is the last level in this simple example. Here we define the funtion compute error called from the second level by compare results. ◦
function err = compute error( res ) % Here should be some (possibly detailed) description. % .... err = .... % here res is used to compute err return;
9.2. Debugging
74
3. Coding. Implement the functions sequentially, i.e. one by one. Turning your algorithm into an efficient code is not a one-shot process. You will have to try, make errors, correct them and even modify the algorithm. So, be patient and test your functions one by one. While implementing, make sure that all your outputs are computed at some point. Remember to insert comments and stick with the style requirements (see section 9.3). 4. Running and debugging (see also section 9.2). Bugs will exist in any newly written program. Never, ever, believe or assume that a code you just created will work. Always check the correctness of each function or script, twice if not thrice. You may add extra lines to your code to present intermediate results (simple displays, plots, writes to files) to help you verify what is going on. Those lines can be out-commented for re-use, or at a later stage can be removed entirely. 5. Testing and Verification. After the debugging process, the testing stage starts. Prepare a number of tests to verify whether your program does what it is expected to do under well-defined conditions. Remember that good tests are those for which the answers are known. Your program should produce correct results for normal test conditions as well as boundary conditions. When writing large code, the amount of code written for testing purposes often exceeds the actual number of lines in the application, and likewise the time spend testing the code often well exceeds the time it took to write the code. 6. Maintenance. In solving your task, new ideas or problems may appear. Some can be interesting and creative, while others can help you to understand the original problem better; you may see an extension to your problem or a way to incorporate new things. If you have a welldesigned code, you will be able to easily modify it after some time. Take the responsibility to improve your code and correct any errors you detect when running it.
9.2
Debugging
Debugging is the process by which you isolate and fix any problem(s) with your code. Four kinds of errors may occur: • Syntax errors. These are violations against the ‘grammar’ of a language. Already while editing a script or function m-file, the Matlab editor will indicate possible syntax errors. Add for instance the following line to one of your m-files: x = 2pi;
There should appear a marker on the right side of the edit window. Moving the cursor over this mark will reveal a message ‘Parse error at ‘pi’: usage appears to be invalid MATLAB syntax’. • Runtime errors These are errors that surface when you perform an incorrect command, like accessing the
9.2. Debugging
75
zeroth element of an array, division by zero, etc. These are fairly easy to detect, as they cause your code to crash. Read the error message and solve the problem. If there are multiple messages, always start at the top; the second message is often a consequence of the first error. Note that the actual error may have occurred one or several lines before the error message. • Coding errors It is easy to make typos (or worse) in a code that prove non-fatal, like replacing an i with a j or a 1. That is, your code will ‘successfully’ run to the end but the output is incorrect. These errors are more difficult to track down because they do not shout ‘I am here.’ Always try to test your code (and individual functions) with input for which you know the correct output. Look at intermediate results to see where things start to go wrong. • Algorithmic errors The worst errors are those where, after a long time of rereading and testing whether the implementation is correct, you arrive at the conclusion that algorithm is flawed. You have to improve the algorithm, or come up with a new one, implement it, and restart the debugging process all over (minus those functions that already passed the tests). Debugging is an inevitable process. The best way to reduce the possibility of making errors is defensive programming: • Do not assume that input is correct, always check.
• Where reasonable and possible, provide a default option or value.
• Provide diagnostic error messages.
• Optionally print intermediate results to check the correctness of your code.
Defensive programming is a part of the early debugging process. Another important part is modularity, i.e. breaking large task into small subtasks, which allows for developing tests for each of them more easily. You should always remember to run the tests again after changes have been made. To make this easy, include extra print statements that can be turned on or off. Matlab provides an interactive debugger. It allows you to set and clear breakpoints, specific lines in an m-file at which the execution of a program will halt (click on the minus-sign in front of a line, it turns into a red circle when a breakpoint is set). You can then run the code till this point, to gain access to the local workspace of a function and to step through the next lines one by one. The debugging process can also be started from the command line. Use the dbstop command to determine what errors to ‘trap’. Particularly useful options are dbstop if error dbstop if infnan
% %
stop at fatal error stop at numerical errors
This will stop your code when an error of the specified type(s) occurs. Rather than returning just the error message, you are dropped in the code at the location of the error. At the command prompt, which has changed into K>>, you can ask for the values of specific variables, to advance a step (dbstep), continue execution (dbcont), etc, to help you find the bug. To leave the debug mode, type dbquit. To clear all debugging flags, and thereby return to Matlab’s default error handling, use dbclear all.
9.3. Recommended programming style
9.3
76
Recommended programming style
Programming style is a set of conventions that programmers follow to standardise their code to some degree and to make the overall program easier to read and to debug. This will also allow you to quickly understand what your program does when you look at it weeks or months from now. The style conventions are for the reader only, but you will become that reader one day. Some style requirements and style guidelines are presented below. These are recommendations, and some personal variations in style are acceptable, but you should not ignore them. It is important to organise your programs properly since it will improve the readability, make the debugging task easier and save time of potential readers. 1. You should always comment difficult parts of the program! But ... do not explain the obvious. 2. Comments describing tricky parts of the code, assumptions or design decisions, are best placed above the part of the code you are documenting. Try to avoid big blocks of comments, except for the description in the m-file header. 3. Indent a few spaces (preferably 2 or 3) all lines of code and comments inside control flow structures. Here is an example: x = 0:0.1:500; for i=1:length(x) if x(i) > 0 s(i) = sqrt(x(i)); else s(i) = 0; end end
The Matlab m-file editor will introduce such spaces by default. To reset the indenting, select all lines (¡ctrl¿¡a¿) and press ¡ctrl¿¡i¿. 4. Avoid the use of magic numbers; use a constant variable instead. When you need to change the value, you will have to do it only once rather than search throughout your code. An example: % A BAD code with magic numbers r = rand(1,50); for i = 1:50 data(i) = i * r(i); end y = sum(data)/50; disp(['Number of points is 50.']);
% This is the way it SHOULD be n = 50; % number of points r = rand(1,n); data = (1:n) .* r; avr = sum(data)/n; disp(['Number of points is ',... int2str(n)]);
Note that a hard-coded 50 will often also give rise to hard-coded 49s and 51s, making it difficult to track down all occurances of your ‘50’. And this gets worse if there are two hard-coded numbers that both happened to be 50 when you wrote the code. 5. Avoid the use of more than one code statement per line in your script or function m-files.
9.4. Commenting and publishing in MATLAB
77
6. No line of code should exceed the screen width (it is a rare case when this is not possible). When necessary, use the Line Continuation Symbol, i.e. the characters ..., at the end of a line of to indicate that the expression continues on the next line. 7. Avoid declaring global variables. You will hardly ever encounter a circumstance under which you will really need them. Global variables can easily get you into trouble without you noticing it! 8. Variables should have meaningful names. You may also use the standard notation, e.g. x, y are real-valued, i, j, k are indices or n is an integer. This will reduce the number of comments and make your code easier to read. However, here are some pitfalls when choosing variable names: • A meaningful variable name is good, but when it gets longer than 15 characters it tends to obscure rather than improve the code readability. • Be careful with names since there might be a conflict with Matlab’s built-in functions or reserved names like mean, end, sum etc. (check in index or ask which in Matlab– if you get the response not found it means that you can safely use it). Note that even the obvious examples i and j overwrite the built-in complex imaginary unit i. • Avoid names that look similar or differ only slightly from each other. 9. Use white spaces, both horizontally and vertically, since it will greatly improve the readability of your program. Use blank lines to separate larger blocks of the code.
9.4
Commenting and publishing in MATLAB
There are various special ways Matlab code can be commented that both aid readability and the ability to find your code (if it forms part of a library). • Firstly the block of code at the top as automatically picked up by Matlabhelp and lookfor commands. • The code can be divided into cells or blocks by inserting two percentage signs %%. For testing purposes each block of code can be separately executed using shift-enter. • The code on the line with %% is the title of that code block
9.4.1
Publishing Matlab code
Matlab code can now to automatically published i.e. converted in to an html document, latex or even word document. This is done via the publish button in the toolbar. When publishing Matlab code there is a few each commenting conventions: • Variables should be preceded and succeeded with an underscore i.e.
k .
• Latex equations can be included using $$ i.e. % $$ sin x = 5 $$ • Each block will appear as a separate section in the published version of the code.
Chapter 10 Matlab and execution speed
Matlab is an interpreted high-level interpreted language. Consequently it is easy to write powerful code, but the execution time of this code can be orders of magnitude larger than that of a similar code written in C++, a low-level compiled language. In an compiler, the whole code is translated from human-readable instructions into the instructions that the processor understands, creating an executable (in windows recognisable by the exe-extension). This executable can then be run directly, without requiring any interaction with the compiler (and you do not even need to have a compiler installed to run the code). An interpreter, on the other hand, translates only one line of code at a time, and does so when you want to execute that line. Hence you spent a lot of effort on translating lines (basically, the inner code in a for loop is translated very often, while some lines in an if might never be translated) which makes the execution of your program a slow affair. And running the code outside the interpreter is not possible. The people at Matlab are aware of this, so they offer possibilities to make your code run quicker if you stick to certain conventions. To recover some of the loss of speed when using Matlab, there are four golden rules: 1. Remove all for-loops where possible; see section 10.1. 2. Use the internal Matlab functions where possible; these are compiled. 3. Pre-allocate all vectors and matrices; see section 10.2. 4. Suppress all non-required output; writing to the screen is very slow. Note that these rules only apply to Matlab code.
10.1
Vectorizing your code
Matlab is slow in executing explicit for loops. It is often possible to avoid loops all together
– 78 –
10.2. Pre-allocation of arrays
79
by using the implicit loops available in Matlab. Consider the following code: >> clear all; >> tic; k=1e7; x=rand(k,1); for i = 1:k; x(i) = sqrt(exp(sqrt(x(i)))); end; toc Elapsed time is 2.020193 seconds.
This calculation can be vectorised by simply writing >> clear all >> tic; k=1e7; x=rand(k,1); x = sqrt(exp(sqrt(x))); Elapsed time is 0.532375 seconds.
toc
The second form runs faster.
10.2
Pre-allocation of arrays
Vectors that grow inside a for-loop can become very slow. A notorious example is concatenation: >> clear all >> tic; k = 1e5; x = []; for i = 1:k ; x=[x i]; end; toc Elapsed time is 9.809436 seconds.
The run time of this piece of code goes like k!, making it extremely slow for large k. A major performance improvement is obtained by rewriting the code as >> clear all >> tic; k = 1e7; for i = 1:k ; x(i) = i; end; toc Elapsed time is 1.261517 seconds.
Note that in this second example the value of k is 100 times as high as in the first example, yet the run time is nearly an order of magnitude shorter. One can gain another order of magnitude by claiming the maximum array size of x before entering the loop, >> clear all >> tic; k=1e7; x(k)=0; for i = 1:k ; x(i) = i; end; toc Elapsed time is 0.104670 seconds.
Exercise 10.1. Write a function to sort a set of n numbers into order. Measure the run time of your code as a function of n, and plot the run time against n on a double logarithmic plot. Compare the performance of your code with that of the internal sort function. Exercise 10.2. Create an (n × n) random matrix. Use a for loop and an if statement to count how many elements in the matrix are greater than 1/2. Measure and plot the run time of your as a function of n. Compare the performance of you code against that of a code using internal function only.
Chapter 11 Visualisation
Matlab includes powerful features for easy figure creation, plotting and image display. These can be used to visualise the results of an experiment or calculation in Matlab. We will start by introducing the most basic features here.
11.1
2D plots
The most important commands for basic 2-dimensional plotting are illustrated in the following example: x=0:0.1:10; y=sin(x); figure plot(y) figure plot(x,y) close
% % % % % % % % %
x ranges from 0 to 10 in steps of 0.1 y contains the sin of each value of x create an empty figure window plots all of the y values (the values on the x−axis are indexes from 1 to 101) create an empty figure window plots y against x (replacing the old plot on the same figure, now showing the units of x on the x−axis) closes the active figure window
Note that x and y can be row and/or column vectors, but must be of the same length. The plot command produced a plot in the active figure window, replacing the existing plot in that window. A new window can be created with figure or figure(5); the latter command can also be used to reactivate figure 5 (which is not necessarily the 5th figure). To plot a graph of a function, it is important to sample the function sufficiently well. Compare the following examples:
– 80 –
11.1. 2D plots
81
1
1 2 3 4 5
% coarse sampling n = 5; x = 0:1/n:3; y = sin(5*x); plot(x,y)
0.8 0.6 0.4 0.2 0 −0.2 −0.4 −0.6 −0.8 −1 0
0.5
1
1.5
2
2.5
3
0.5
1
1.5
2
2.5
3
1 0.8 0.6
1 2 3 4 5
% good sampling n = 25; x = 0:1/n:3; y = sin(5*x); plot(x,y)
0.4 0.2 0 −0.2 −0.4 −0.6 −0.8 −1 0
The plot command has many additional possible arguments, as can be seen by typing help plot. A list of common auxiliary commands is provided in Table 11.1. There are also many other plotting commands for 2-dimensional plotting (help graph2d) and also for 3-D plotting (help graph3d). You can close a figure window by clicking on the upper right X box, using the ‘close’ command on the figure’s file menu, or by typing close at the command prompt. Use close all to close all figures and start a new task, or use close 3 to close Figure no.3. To clean a plot without closing the window, use cla. The colour and point marker can be changed on a plot by adding a third parameter (in single quotes) to the plot command. A list of colours and styles is reported in Table 11.2. For example, Command grid on/off box off/on axis([xmin xmax ymin ymax]) xlabel(’text’) ylabel(’text’) zlabel(’text’) title(’text’) text(x,y,’text’) gtext(’text’) legend(’fun1’,’fun2’) legend off clf figure(n) subplot
Result adds a grid to the plot at the tick marks or removes it removes the axes box or shows it sets the minimum and maximum values of the axes plots the label text on the x-axis plots the label text on the y-axis plots the label text on the z-axis plots a title above the graph adds text at the point (x,y) adds text at a manually (with a mouse) indicated point plots a legend box (move it with your mouse) to name your functions deletes the legend box clear the current figure creates a figure #n or activates existing figure #n. creates a subplot in the current figure
Table 11.1: Useful commands when making plots.
11.2. Several functions in one figure Symbol r g b y m c k
Color red green blue yellow magenta cyan black
82 Symbol ., o * x, + -: -.
Line style point, circle star x-mark, plus solid line dash line dot line dash-dot line
Table 11.2: Plot colors and styles. to plot the function as a red, dotted line, x = 0:0.1:100; y = 3*x; plot(x,y,'r:')
11.2
Several functions in one figure
You can plot more than one function in the same figure. To plot a sine wave and cosine wave on the same set of axes, using a different color and point marker for each, the following m-file can be used: x = 1:0.1:2*pi; y = sin(x); z = cos(x); plot(x,y,'r', x,z,'gx')
By adding more sets of parameters to plot, you can plot as many different functions on the same figure as you want. The same effect can also be achieved using the hold on and hold off commands. The same plot shown above could be generated using the following m-file: x = linspace(0,2*pi,50); y = sin(x); z = cos(x); hold on plot(x,y,'r') plot(x,z,'gx') hold off
Always remember that if you use the hold on command, all plots from then on will be generated on one set of axes, without erasing the previous plot, until the hold off command is issued. When plotting many data sets in the same graph it is useful to differentiate the various functions by colour and markers.
11.3. Adding text
83
It is also possible to produce several subplots in one figure window. With the command subplot, the window can be horizontally and vertically divided into x × y subfigures, which are counted from 1 to x ∗ y, row-wise, starting from the top left. The commands: plot, title, grid etc work only in the current subfigure. So, if you want to change something in another subfigure, use the command subplot to switch there. x = 1:.1:4; y1 = sin(3*x); y2 = cos(5*x); y3 = sin(3*x).*cos(5*x); figure subplot(1,3,1); plot(x,y1,'m'); title('sin(3*x)') subplot(1,3,2); plot(x,y2,'g'); title('cos(5*x)') subplot(1,3,3); plot(x,y3,'k'); title('sin(3*x) * cos(5*x)')
11.3
Adding text
Another thing that may be important for your plots is labeling. You can give your plot a title (with the title command), x-axis label (with the xlabel command), y-axis label (with the ylabel command), and put text on the actual plot. All of the above commands are issued after the actual plot command has been issued. Text can be put on the plot itself in one of two ways. The text(xcor,ycor,’textstring’) command involves knowing the coordinates of where you want the text string to appear (in terms of the coordinate values along the axes of the plot). With gtext(’textstring’) you use the mouse to select a position. To add a title, grid and to label the axes, one uses: x=0:0.1:3; y=sin(x); z=cos(x); hold on; plot(x,y); plot(x,z); title('Sine and Cosine') xlabel('x') ylabel('sin(x) and cos(x)') gtext('unnecessary labeling') legend('sin','cos')
To drop the text ‘unnecessary labelling’, place the mouse in the figure window and click on the desired spot. Note that LATEX-style commands are accepted, e.g. xlabel(’\alpha^2’) to produce the label α2 .
11.4. Changing the axes
11.4
84
Changing the axes
The commands loglog, semilogx and semilogy are similar to plot, except that they use either one or two logarithmic axes. An important way to customise your plots to meet your needs is by the axis, xlim and ylim commands. They change the range of the plot to be shown, so only the desired part of the graph is displayed. The command(s) apply to the currently active plot. axis([xmin, xmax, ymin, ymax]) axis('auto x') xlim([−Inf,3]) ylim('auto')
The options -Inf, +Inf and auto leave the decision to Matlab. The axes can also be adjusted interactively.
11.5
Fine-tuning plots
Matlab automatically formats a graph to provide readability, sets the scales of the axes, includes tick marks on the axes, and uses color and line style to distinguish the plots in the graph. However, you may want to change this default formatting or add descriptive labels, titles, legends and other annotations to help explain your data. Matlab supports three ways to edit the plots you create:
• Property Editor to select and edit objects interactively. • Matlab functions at the command-line or in an M-file (look at ”Line Properties” in the help for the list of properties). figure hold on x = 1:.1:4; h1 = plot(x,cos(x)) h2 = plot(x,sin(x)) set(h1,'LineWidth',2,'LineStyle','.','Color','g') set(h2,'LineWidth',2,'LineStyle','ˆ','Color','r') hold off
In this example, h1 and h2 are handles (basically pointers to objects, see the C++ part of the course). We happily ignore the values Matlab returns to command window when the handle is created. The function get(h1) returns all properties of the handle h1, which can then be adjusted by set(h1,...) to touch up the plot. Alternatively, click on h1 in the workspace to interactively set the values. • One may also use figure handle for additional tuning, see Section 7.3.
11.6. Saving graphics
11.6
85
Saving graphics
To store a figure, so one can resume editing at a later time, simply type savefig(’filename’) and Matlab will add the extension ‘.fig’. This will store the plotted data as well as all makeup. Use openfig(’filename’) to open the figure and continue where you left off. One can also use open(’filename.fig’), where the extension is obligatory. Similar save and open options are also available interactively. When handles are available to access figures, one may use either hgsave(h1,’filename’) or saveas(h1,’filename’) to save the figure and h1=hgload(’filename’) to reload it.
11.7
Exporting graphics
To copy the plot into Word you can select directly on the figure Edit → Copy Figure
You can also ‘print’ to file by specifying a file name. From the command line, print achieves the same result. Since they are many parameters, they will not be explained here (check help print to learn more). Instead, try to understand the examples: % print the current Figure to the current printer in color print −dwinc % print Figure no.1 to file in encapsulated postscript, black and white print −f1 −deps myfile.eps % print Figure no.1 to file in encapsulated postscript, color print −f1 −depsc myfilec.eps % print the current Figure in a picture format print −dtiff myfile1.tiff % print the current Figure in postscript, color print −dpsc myfile1c.ps % print Figure no.2 in a picture format print −f2 −djpeg myfile2
11.8
Plotting surfaces
Matlab provides a number of commands to plot 3D data. Some surfaces can be defined by a function f (x, y), where for each pair of (x, y), the height z is computed as z = f (x, y). To plot a surface, a rectangular domain of the (x, y)-plane should be sampled. The mesh (or grid) is constructed by using the command meshgrid as follows: [X, Y] = meshgrid (−1:.5:1, 0:.5:2) X = −1.0000 −0.5000 0 0.5000 −1.0000 −0.5000 0 0.5000
1.0000 1.0000
11.8. Plotting surfaces −1.0000 −1.0000 −1.0000 Y = 0 0.5000 1.0000 1.5000 2.0000
86
−0.5000 −0.5000 −0.5000
0 0 0
0.5000 0.5000 0.5000
1.0000 1.0000 1.0000
0 0.5000 1.0000 1.5000 2.0000
0 0.5000 1.0000 1.5000 2.0000
0 0.5000 1.0000 1.5000 2.0000
0 0.5000 1.0000 1.5000 2.0000
Next, we calculate the heights z corresponding to these (x, y) pairs and plot the surface with the command mesh or surf: [X,Y] = meshgrid(−1:.05:1, 0:.05:2); Z = sin(5*X) .* cos(2*Y); mesh(X,Y,Z); title ('Function z = sin(5x) * cos(2y)')
Use colormap to define different colours for plotting. More general, a 2D surface in a 3D space can be described by two curvi-linear coordinates (u, v) with the 3D Cartesian coordinates calculated as x = x(u, v), y = y(u, v) and z = z(u, v). The ensuing calculations are similar to the above example, see exercise 11.11. Returning to z = f (x, y), a 2D contour plot displays isolines calculated from the matrix z. [X,Y] = meshgrid(−2:.05:2,−2:.05:3); Z = X.*exp(−X.ˆ2−Y.ˆ2); figure contour(X,Y,Z,15) % just the contour lines figure contourf(X,Y,Z,25) % with 'filled' area colormap hsv close
3
3
2.5
2.5
2
2
1.5
1.5
1
1
0.5
0.5
0
0
−0.5
−0.5
−1
−1
−1.5
−1.5
−2 −2
−1.5
−1
−0.5
0
0.5
1
1.5
2
−2 −2
−1.5
−1
−0.5
0
0.5
1
1.5
2
Figure 11.1: Output of the contour and contourf example If you like the coloured filling but don’t like the contour lines, they can be turned off by adding the two (comma separated) keywords ’EdgeColor’ and ’none’ to contourf [ or contour :-) ].
11.9. 3D line plots
87
To locate e.g. the minimum value of the function the function z = x exp(−x2 − y 2 ) on the grid, you can proceed as follows: [X,Y] = meshgrid(−2:.05:2,−2:.05:3); Z = X.*exp(−X.ˆ2−Y.ˆ2); [mm,I] = min(Z); % a row vector of the min. elements from each column % I is a vector of corresponding [∼, j] = min (mm); % j is the index of the minimum value; the tilde sign % suppresses the output of the minimum value itself xpos = X(I(j),j); % ypos = Y(I(j),j); % position of the minimum value contour (X,Y,Z,25); xlabel('x−axis'); ylabel('y−axis'); hold on plot(xpos,ypos,'*'); text(xpos+0.1,ypos,'Minimum'); hold off
11.9
3D line plots
The command plot3 to plot lines in 3D is equivalent to the command plot in 2D. The format is the same as for plot, be it with an extra coordinate. An example is plotting the curve r defined parametrically as r(t) = [t sin(t), t cos(t), t] over the interval [−10 π, 10 π]. t = linspace(−10*pi,10*pi,200); plot3(t.*sin(t), t.*cos(t), t, 'md−'); % plot the curve in magenta title('Curve r(t) = [t sin(t), t cos(t), t]'); xlabel('x−axis'); ylabel('y−axis'); zlabel('z−axis'); grid
11.10
Animations
You can make a movie using Matlab by saving a sequence of graphs into a video file. To do this, create a VideoWriter variable that stores the properties of the video file, such as frame rate, container type (typically avi), compression type (if in doubt, use ’none’). Use open(videoWriter) to create the video file and writeVideo(videoWriter,frame); to write frames into a video file, then close it with close(videoWriter). Frames are rgb images, and can be created from a figure using the get frame command (see doc getframe). All frames need to be the same size, which is enforced by the command set(gca,’nextplot’,’replacechildren’). Example 11.1: Create a movie of an evolving function curve in the interval 4 π. videoWriter = VideoWriter('video.avi'); %create VideoWriter object videoWriter.FrameRate=10; %change properties like the frame rate open(videoWriter); %open avi file for writing
11.11. Exercises
88
%Generate initial data and set axes and figure properties. x=linspace(−pi,pi,30); y=x; [X,Y]=meshgrid(x,y); Z=sin(X).*cos(Y); surf(X,Y,Z) set(gca,'nextplot','replacechildren'); %enforces a constant axis size %set(gcf,'Renderer','zbuffer'); %needed on some windows systems axis tight % Create a set of frames and write each frame to the file. for t = 0:0.02:1 surf(X,Y,sin(2*pi*t)*Z) frame = getframe % converts figure content into rgb values writeVideo(videoWriter,frame); %write a frame into the avi file end close(videoWriter); % close the avi file
11.11
Exercises
Exercise 11.1. Make a plot connecting the coordinates: (2, 6), (2.5, 18), (5, 17.5), (4.2, 12.5) and (2,12) by a line. Exercise 11.2. Plot the function y = sin(x) + x − x cos(x) in two separate figures for the intervals: 0 < x < 30 and −100 < x < 100. Add a title and axes description. Exercise 11.3. Plot a circle with the radius r = 2, knowing that the parametric equation of a circle is [x(t), y(t)] = [r cos(t), r sin(t)] for t = [0, 2π]. Exercise 11.4. Plot an ellipse with semiaxes a = 4 and b = 2. Exercise 11.5. 2 Plot the functions f (x) = x, g(x) = x3 , h(x) = ex and z(x) = ex over the interval [0, 4] on the normal scale and on the log-log scale. Use an appropriate sampling to get smooth curves. Describe your plots by using the functions: xlabel, ylabel, title and legend. Exercise 11.6. Make a plot of the functions: f (x) = sin(1/x) and f (x) = cos(1/x) over the interval [0.01, 0.1]. How do you create x so that the plots look sufficiently smooth? Exercise 11.7. Produce a nice graph which demonstrates as clearly as possible the behavior of the function y2 f (x, y) = xx2 +y 4 near the point (0, 0). Note that the sampling around this points should be dense enough.
11.11. Exercises
89
Exercise 11.8. Plot a sphere, which is parametrically defined as [x(t, s), y(t, s), z(t, s)] = [cos(t)∗cos(s), cos(t)∗ sin(s), sin(t)] for t, s = [0, 2 π], using surf. Make first equal axes, then remove them. Use shading interp to remove the grid of black lines (to restore the original picture, use shading faceted). Exercise 11.9. Plot the following parametric function of r and θ: [x(r, θ), y(r, θ), z(r, θ)] = [r cos(θ), r sin(θ), sin(6 cos(r) − nθ)] for θ = [0, 2 π] and r = [0, 4]. Choose n to be constant. Observe, how the graph changes depending on different n. Exercise 11.10. 2 2 Plot the surface f (x, y) = x y e−x −y over the domain [−2, 2] × [−2, 2]. Find the values and the locations of the minima and maxima of this function. Exercise 11.11. Make a 3D smooth plot of the curve defined parametrically as: [x(t), y(t), z(t)] = [sin(t), cos(t), sin2 (t)] for t = [0, 2π]. Plot the curve in green, with the points marked by circles. Add a title, description of axes and the grid. You can rotate the image by clicking Tools at the Figure window and choosing the Rotate 3D option or by typing rotate3D at the prompt. Then by clicking at the image and dragging your mouse you can rotate the axes. Experiment with this option. Exercise 11.12. Write a script that makes a movie consisting of 5 frames of the surface f (x, y) = sin(nx) sin(ky) over the domain [0, 2π] × [0, 2π] and n = 1 : 5. Add a title, description of axes and shading. Exercise 11.13. Plot an equilateral triangle with two vertices [a a] and [b a]. Find the third vertex. Use fill to paint the triangle.
Chapter 12 Numerical analysis
Numerical analysis can be used whenever the analytic solution to a problem is difficult or impossible to determine. This is often the case when analysing experimental results. Matlab can be used to find, for example, the minimum, maximum or integral of a certain function or of a set of experimental data. In this section we will briefly discuss some methods on numerical differentiation and integration, as well as the possibility to solve differential equations numerically.
12.1
Differentiation
The derivative of a function f (x), df (x) dx measures the slope of the function at point x. Assuming out x values are equidistant, as illustrated in figure fig:numdiff, the three common approaches to calculating the derivative at xk are: f ′ (x) =
backward difference : f ′ (xk ) ≈ forward difference : f ′ (xk ) ≈ central difference : f ′ (xk ) ≈
f (xk ) − f (xk−1 ) xk − xk−1
f (xk+1 ) − f (xk ) xk+1 − xk
f (xk+1 ) − f (xk−1 ) xk+1 − xk−1
(12.1)
The Matlab function diff(x) computes the differences between adjacent values of the vector x. If the values of f (x) are contained in vector y and the corresponding x values in vector x, the derivative of the function can be estimated using >> dydx = diff(y) ./ diff(x);
– 90 –
12.1. Differentiation
91
Figure 12.1: Three points that can be used in the numerical evaluation of the derivative of function f at point xk , see equation 12.1.
The resulting vector dydx contains one element less than x. The corresponding x values are obtained from the original x vector by trimming either the first or the last value: • trimming the last value results in the forward difference estimate.
• trimming the first value results in the backward difference estimate.
To obtain and plot the derivative of a function f (x) = 5 cos(10x) + x3 − 2x2 − 6x + 10, >> >> >> >> >> >> >> >> >> >> >> >> >>
x = 0:.01:4; y = 5*cos(10*x) + x.ˆ3 − 2*x.ˆ2 − 6*x + 10; subplot(2,1,1) plot(x,y) title('f(x)') dydx = diff(y) ./ diff(x); xx = x(2:end); % Backward difference x values subplot(2,1,2) plot(xx,dydx) title('df/dx') hold on yy = −50*sin(10*x) + 3*x.ˆ2 − 4*x − 6; % The exact derivative plot(xx,yy,'r') % Nice agreement, hopefully
Exercise 12.1. Type and run the above script. Try and explain the following calculation of the derivative: >> dydx = ( y(3:end) − y(1:end−2) ) ./ ( x(3:end) − x(1:end−2) ); >> plot(x(2:end−1,dydx)
Exercise 12.2. Measurement data often contains noise. We can simulate this by adding random numbers to our smooth data,
12.2. Integration
92
>> z = y + ( rand(1,length(y) − 0.5 ) % >> dzdx = diff(z)./diff(x);
Include the calculation and plot commands of z and its numerical derivative dzdx in the above script and run it. Does your result improve upon decreasing the step size? What do you conclude from the graphs, and can you explain this?
12.2
Integration
The integral of a function f (x), i.e the surface between the x-as and a 2D plot of this function, can also be determined numerically. A number of algorithms exists to calculate the numerical values of definite integrals, some of which are displayed in figure fig:integ and explained below.
• Rectangle rule: the interpolating function is a constant function, i.e. a polynomial of degree zero, passing through the point (m, f (m)), with m = (a + b)/2. Then Z a f (x)dx ≈ (b − a) · f (m). b
• Trapezoidal rule: the interpolating function is a straight line, i.e. a polynomial of degree one, passing through the end points (a, f (a)) and (b, f (b)). Then Z a 1 f (x)dx ≈ (b − a) · [f (a) + f (b)] . 2 b
Figure 12.2: Illustrations of numerical integration by, from left to right, the rectangle rule, trapezoidal rule and Simpson’s rule. In the top row the range from a to b is treated as one interval, in the bottom row as two equal-width intervals.
12.3. Solving differential equations - the ODE toolbox
93
• Simpson’s rule: the interpolating function is a polynomial of degree two passes through the end points (a, f (a)) and (b, f (b)) as well as the midpoint (m, f (m)). Then Z a 1 f (x)dx ≈ (b − a) · [f (a) + 4f (m) + f (b)] . 6 b As can be clearly seen in the figure, the accuracies of the various methods can be increased by dividing the interval (a, b) into multiple sub-intervals, computing approximated areas for all sub-intervals and then adding up all the partial results.
12.2.1
Matlab commands
Matlab has several commands to determine the integral of a function. One of these commands is trapz, which uses the trapezoidal rule, >> x = 0:0.5:10; y = 0.5 * sqrt(x) + x .* sin(x); >> int1 = trapz(x,y) int1 = 18.1655 >> x = 0:0.05:10; y = 0.5 * sqrt(x) + x .* sin(x); >> int2 = trapz(x,y) int2 = 18.3846
Evidently, the accuracy of the computed integral depends on the distance between consecutive data points. A more accurate result is obtained by using the command integral, which numerically evaluates the integral of a function using an adapted Simpson’s rule. Where the input for trapz consists of two vectors, we sent a function as input to integral, as illustrated by the following example. >> f = @(x) 0.5*sqrt(x) + x.*sin(x) f = function handle with value: @(a)0.5*sqrt(x)+x.*sin(x) >> f([1 2 3]) >> int3 = integral(f,0,10) int3 = 18.3876
12.3
% Integral requires dot operators
% Test of dot operators
Solving differential equations - the ODE toolbox
Without going into mathematical details, we want to point out that one has to be very careful when using Matlab’s ODE toolbox as a black box solver for ordinary differential equations (ODEs). It is e.g. important to distinguish between so-called stiff and non-stiff ODEs. Numerical methods that work perfectly fine for non-stiff ODEs can become numerically unstable when applied to stiff equations, unless the integration step is taken to be extremely small. Here
12.3. Solving differential equations - the ODE toolbox
94
we discuss the ode45 solver, based on the Runge-Kutta method, which can be used for nonstiff problems only. Note that Matlab provides dedicated solvers for stiff ODEs, like ode15s, ode23s, ode23t and ode23tb.
12.3.1
First order ODE
Example 12.1: Solve the following ODE of first order dy = x y 2 + y, dx
with boundary condition
y(x = 0) = 1,
in the interval x ∈ [ 0, 0.5 ]. For any differential equation of the form dy/dx = f (x, y), we begin by defining the function f (x, y). In this particular case, f (x, y) is sufficiently compact to be defined as an inline function, which simplifies the procedure. The basic usage for Matlab’s solver ode45 is ode45(function,domain,initial condition)
Thus, we can formulate the problem as >> f = inline('x*yˆ2+y'); >> [x,y] = ode45( f, [0 0.5], 1 ); >> plot(x,y)
% ode45 does not require dot operators
To ‘solve’ the ODE numerically, ode45 feeds an intermediate point (x, y) to your function, so upon receiving the derivative at that point in reply it can take an integration step to arrive at the next point (x, y), and so on. Note that ode45 has selected a certain optimized (non-equidistant) discretization x on the interval [ 0, 0.5 ] and it has returned in y the approximate values of y(x) at each point in this x-partition. Exercise 12.3. Create a handle to a function f accepting two input arguments x and y for the above function f (x, y). Pass this handle to ode45 to numerically solve the ODE. Rather than the array of x values selected by ode45, we are often interested in the value of y at values of x that we select ourselves. For example, we might only want to approximate the solution at six equidistant points, x = 0, 0.1, . . . , 0.5. We can specify this by entering the corresponding x vector as the domain in ode45, >> f = inline('x*yˆ2+y'); >> [x,y] = ode45( f, [ 0 : 0.1 : 0.5 ], 1 ); >> plot(x,y)
Note that Matlab continues to use roughly the same partition of x values that it originally chose, as that was the set required to approximate the solution to within the requested accuracy. The only thing that has changed are the x values at which ode45 returns an approximation of y.
12.3. Solving differential equations - the ODE toolbox
95
Several options are available for Matlab’s ode45 solver, thereby providing the user limited control over the algorithm. Two important options are the relative and absolute tolerances, RelTol and AbsTol respectively. In each step of the ode45 algorithm, the error in that step is approximated. If yk is the approximation of y(xk ) at step k, and ek is the approximate error at this step, then ode45 chooses its partition of x to insure that ek ≤ max(RelTol ∗ yk , AbsTol), where the default values are RelTol = 1e-3 and AbsTol = 1e-6. As an example where we might want to change these values, observe that for large yk the error ek may be allowed to grow quite large. In this case, one can increase the value of RelTol. For the above problem dy/dx = xy 2 + y with y(0) = 1, the values of y become quite large as x approaches 1: >> f = inline('x*yˆ2+y'); >> [x,y] = ode45( f, [0 1], 1 ); Warning: Failure at t=9.999897e−001. Unable to meet integration tolerances without reducing the step size below the smallest value allowed (1.776357e−015) at time t. > In ode45 (line 308)
In order to fix this problem,1 we can choose a smaller value for RelTol, >> f = inline('x*yˆ2+y'); >> options = odeset( 'RelTol', 1e−10 ); >> [x,y]= ode45( f, [0 1], 1, options );
Plot this result; you might want the terminate the vertical axis at, say, y = 100.
12.3.2
Systems of ODE
Solving a system of coupled ODEs in Matlab is quite similar to solving a single equation. Since a system of equations is often not readily defined as an inline function, we supply the derivatives to ode45 in an m-file. As an example, let’s solve the system of Lorenz equations (these equations are a simplified model for atmospherics; their solutions have long served as an example of chaotic behaviour), dx = −σx + σy, dt dy = ρx − y − xz, dt dz = −βz + xy. dt
(12.2)
For the purposes of this example, we will take σ = 10, β = 8/3 and ρ = 28, in combination with the starting point x(0) = −8, y(0) = 8 and z(0) = 27. First, a Matlab M-file lorenz.m is created that contains the Lorenz equations function v = lorenz(t,w); %LORENZ: Defines the Lorenz equations. 1
Note that ode45 refers to the independent coordinate, our x, as ‘time’ and t.
12.4. Exercises
96
sig = 10; beta = 8/3; rho = 28; v = [ −sig*w(1) + sig*w(2); rho*w(1) − w(2) − w(1)*w(3); −beta*w(3) + w(1)*w(2)];
Observe that the three dependent variables x, y and z are combined into the vector w, and that the derivatives are returned (to ode45) in the column vector v. Additionally, any function used in combination with the ode family must receive the independent and dependent coordinates as the first and second input argument, respectively, even if these coordinates are not actually used (as is t in the current example). Now, the solution of this system of ODEs over the interval t = [0, 20] can be calculated: >> x0 = [ −8 8 27 ]; >> tspan = [ 0, 20 ]; >> [ t, xyz ] = ode45( @lorenz, tspan, x0 );
Note that on the last line a handle to our function is passed to ode45. The output consists of a column t of times and a matrix xyz with three columns containing the values of x, y and z at these times. Exercise 12.4. Create a figure with three subplots and plot the three coordinates as functions of t. Create a separate figure for a 3D line plot of the three coordinates. Exercise 12.5. Simply type the following >> x0 = [ −8 8 27 ]; >> tspan = [ 0, 20 ]; >> ode45( @lorenz, tspan, x0 );
That is, do not store the output of ode45 and simply observe what happens. Exercise 12.6. Now type >> x0=[−8 8 27]; >> tspan=[0,20]; >> MyObject=ode45(@lorenz,tspan,x0);
Have a look ‘inside’ MyObject to see what information it contains about the calculation.
12.4
Exercises
Exercise 12.7. Determine the first and second derivative of the line through (x,y) with x = 4:13 and y = [12.84 12.00 7.24 -0.96 -11.16 -20.96 -27.00 -24.96 -9.56 25.44]. Make a figure
12.4. Exercises
97
containing the plot of the initial data, the first derivative, and the second derivative in separate sub-plots. Exercise 12.8. Make a figure containing 2 sub-plots, and plot the function sin(x)/x and its integral on the interval [0, 10]. Find the location of the roots of f(x) and mark the values corresponding to the roots in each figure. Exercise 12.9. Write scripts that compute the integral of the function f (x) = (1 + x2 )−1 using the Rectangle rule, the trapezoidal rule and Simpson’s rule. Use the scripts to find the integral over the interval [0, 4]. Exercise with different accuracies (number of subintervals) and compare the results with the analytical value of the integral. Exercise 12.10. Adapt the scripts you prepared for the trapezoidal rule and the Simpson’s rule to determine the integral of f (x) = sin(x) over the interval [0, π2 ]. Do this with different numbers of subintervals; n=[2 4 8 16 32 64 128 256]. For both the trapezoidal rule and Simpson’s rule, create a matrix with 4 rows containing the values of n, the approximation of the integral, the error of the approximation, and the ratio between the errors of consecutive approximations. What does this tell you about the accuracy of both methods? Exercise 12.11. 2 Find the integral of the function f (x) = e−x /2 over the interval [−3, 3]. Exercise 12.12. Make an m-file defining the function y = sin(x5 + x3 ). Then use integral to determine the integral of this function over the interval [0, 2]. Also try to find the exact value of the integral using the symbolic toolbox. Why can numerical integration be useful, even though it results in an approximation of the integral? Exercise 12.13. Solve the following ODE of 1st order dy = x y 2 + y, dx
y0 := y(x = 0) = 1,
in the domain x ∈ [ 0, 0.9 ] with an equidistant discretization of ∆x = 0.01. Use a m-file firstode.m to define the function. Plot the result. Exercise 12.14. The predator-prey model describes the evolution of the number of predators and preys over time. With prey defined as x and predator as y, the number of predators and preys can be modelled with the following system of ODE: dx = αx(1 − y) dt (12.3) dy = βy(x − 1) dt where for the purposes of this example, we will take α = 5 and β = 1 in combination with the starting point x(0) = 3 and y(0) = 1. Solve the predator-prey model over the interval t = [0, 10] and plot the populations of preys and predators in a single graph.
Chapter 13 Symbolic computation
In the previous chapters we used Matlab as a numerical toolbox. Recent versions of Matlab also permit symbolic manipulations of mathematical expressions. That is, Matlab can solve √ the roots of f (x) = x2 + 2x − 1 = 0 as −1 ± 2, rather than as -2.4142. . . and 0.4142. . . , and it can return the derivative and integral of this function as 2 ∗ x + 1 and (x ∗ (x2 + 3 ∗ x − 3))/3, respectively. In this chapter we explain how this works.1
13.1
Symbolic objects
A symbolic object can be a variable, a number or an expression made of symbolic variables and numbers. These objects can be defined using sym or syms, as in >> a = sym('a') a = a >> syms b c >> d = a+5 d = a+5 >> e = 3; >> f = a+d+e f = 2*a + 8
% identical to b = sym('b'), c=sym('c'), but no 'echo'
As usual, Matlab displays the result of the expressions if this is not suppressed by a semi-colon. A difference is that displayed symbolic objects are not indented. Exercise 13.1. √ Clear your workspace and define the symbolic variables x, y and z, where z = x + y + 5. 1
This section contains some examples from the tutorial of W.R. Wilcox, Clarkson University.
– 98 –
13.2. Solving symbolic expressions
99
√ Furthermore, define the (normal) variable a as 5. Finally, try who and whos and note in what respect(s) symbolic variables differ from the non-symbolic ones. Creating symbolic expressions is easy: >> syms x y >> f = xˆ2 + yˆ2 + 3/2 f = xˆ2 + yˆ2 + 3/2 >> g(x) = (1/3)*xˆ2 − 5/4 g(x) = xˆ2/3 − 5/4 >> h = f+g h(x) = (4*xˆ2)/3 + yˆ2 + 1/4 4/3*xˆ2+yˆ2+1/4
% A symbolic expression
% Another symbolic expression
So we see that it does these simple calculations exactly. Note that g and h are of type symfun, while f is of type sym; Matlab will evaluate g(5) but not f(5). Symbolic functions can also be defined directly, syms f(x). Exercise 13.2. Define the symbolic expressions f = x3 + 3x2 + 3x + 1 and g = (x + 1)2 . Next calculate f + g, f − g, f ∗ g, and f /g. As you might have noticed in the last exercise, the symbolic expression are not simplified and only simple calculations are performed directly. Exercise 13.3. Use simplify to simplify the answers to the previous exercise.
13.2
Solving symbolic expressions
A recurring problem is the solution of symbolic expressions. This is made easy with the solve command. By default the command solve(eq) solves the equation eq = 0. >> syms x y >> solve( exp(x)−5 ) % This solves ans = log(5) % Note: log = >> solve( x+y−5 ) % This solves ans = 5−y >> solve( x+y == 5, y ) % This solves ans = 5 − x >> f = xˆ2 + 3*x + 2; >> xzero = solve(f) xzero = −2 −1 >> yzero = solve( yˆ2 + 3*y + 6 ) yzero =
exp(x)=5 ln, log10 = log x+y=5 for x
x+y = 5 for y
13.3. Matrix and and vector operations
100
− (15ˆ(1/2)*1i)/2 − 3/2 (15ˆ(1/2)*1i)/2 − 3/2
We see that the solutions to these expressions are again symbolic objects. The results in xzero are easy to understand, but those in yzero are not immediately clear. For a slightly prettier presentation of these results, use pretty. To recover numerical values, use double. Exercise 13.4. Find the roots of x2 + 4x + 2 and those of x2 + 2x + 4. Calculate the absolute values of all four roots. Which root has the largest absolute value? It is also possible to solve systems of coupled equations, as in >> syms x y >> [x,y] = solve( x+y == 5, x−y == 3, x, y ) x = 4 y = 1
Exercise 13.5. Determine the intersection points of the line x + 3y = 1 with the circle x2 + y 2 = 2. Note that this will not work when the old solutions x and y are still in memory; you have to clear the workspace often for the symbolic manipulations to operate properly.
13.3
Matrix and and vector operations
Since Matlab is matrix-based, it ought not surprise us that it can symbolically manipulate matrices. For example, for the matrix A and the vector x in two dimensions: >> syms a11 a12 a21 a22 x1 x2 >> A=[a11 a12;a21 a22]; >> x=[x1;x2]; >> x' ans = [ conj(x1), conj(x2)] >> x.' ans = [ x1, x2] >> A' ans = [ conj(a11), conj(a21)] [ conj(a12), conj(a22)] >> A.' ans = [ a11, a21] [ a12, a22] >> det(A) ans = a11*a22−a12*a21 >> simple(inv(A)) ans = [ a22/(a11*a22−a12*a21), −a12/(a11*a22−a12*a21)]
13.4. Differentiation and integration [ −a21/(a11*a22−a12*a21), >>A*x ans = a11*x1+a12*x2 a21*x1+a22*x2
101
a11/(a11*a22−a12*a21)]
Note that Matlab considers each declared variable as a complex number. However, in many cases we know that the declared variables are real numbers, and we can tell Matlab so by adjusting the variable declarations. As in illustration, we calculate the dot and cross products of two three-dimensional vectors x and y, >> sysm x1 x2 x3 real; >> syms y1 y2 y3 real; >> e1 = [1;0;0]; e2 = [0;1;0]; e3 = [0;0;1]; % Cartesian basis vectors >> x = x1*e1 + x2*e2 + x3*e3 % combine components and basis x = [ x1, x2, x3] >> y = y1*e1+y2*e2+y3*e3; >> dot(x,y) ans = x1*y1+x2*y2+x3*y3 >> cross(x,y) ans = [ x2*y3 − x3*y2, x3*y1 − x1*y3, x1*y2 − x2*y1]
Exercise 13.6. Evaluate the dot and cross products of two complex-valued three-dimensional vectors x and y. Note the difference(s) to the above answers.
13.4
Differentiation and integration
The symbolic toolbox is nice for solving calculus problems. For example, to differentiate the function f = e−ax x3b sin(cx), with unspecified constants a, b and c, we type >> clear, syms a b c x; >> f(x) = exp(−a*x)*xˆ(3*b)*sin(c*x); >> Df = diff(f) % Or: diff(f,x) Df(x) = 3*b*xˆ(3*b − 1)*exp(−a*x)*sin(c*x) + c*xˆ(3*b)*exp(−a*x)*cos(c*x) ... − a*xˆ(3*b)*exp(−a*x)*sin(c*x) >> Df = simplify( Df ) Df(x) = xˆ(3*b − 1)*exp(−a*x)*(3*b*sin(c*x) + c*x*cos(c*x) − a*x*sin(c*x))
Higher order derivatives are also available, e.g. d2 f /dx2 becomes diff(f,x,2). For more information on symbolic differentiation, see help sym/diff (not to be confused with help diff). For a given function f (x), we solve the indefinite integral F (x) = >> syms a b x; >> f(x) = exp(−a*x)*sin(b*x); >> If(x) = int(f); % Or: int(f,x) If(x) = −(exp(−a*x)*(b*cos(b*x) + a*sin(b*x)))/(aˆ2 + bˆ2)
R
f (x′ ) dx′ as follows:
13.5. Limits
102
Verify this result by asking Matlab to differentiate the integral, diff(If,x). This should recover f , but the result appears to be different because Matlab does not always present the simplest format. Agreement is observed once we simplify the integral. Note that Matlab does not automatically add the constant of integration, c, customarily included in indefinite integrals (whose value is to be deduced from the boundary conditions). If a constant of integration is required, you must add this yourself to If. For integrals Matlab is unable to solve symbolically, it returns a trivial result, >> clear, syms a b c x; >> f(x) = exp(−a*x)*xˆ(3*b)*sin(c*x); >> If = int(f) If(x) = int(xˆ(3*b)*exp(−a*x)*sin(c*x), x)
% Or: int(f,x)
When this happens, you’re out of luck – but you can still obtain a numerical approximation using the methods of the previous chapter. It can happen that the symbolic integral becomes solvable after subsequent manipulations. For definite integrals, F =
Rb a
f (x′ ) dx′ , one appends the range to the integration command,
>> clear, syms a c x; >> f(x) = exp(−a*x)*sin(c*x) >> If = int(f,−pi,pi) % Or int(f,x,−pi,pi) If = (exp(pi*a)*(c*cos(pi*c) − a*sin(pi*c)))/(aˆ2 + cˆ2) ... − (exp(−pi*a)*(c*cos(pi*c) + a*sin(pi*c)))/(aˆ2 + cˆ2)
Exercise 13.7. Solve the integral from section 12.2.1 analytically, and compare the result with the numerical values calculated in that section.
13.5
Limits
The symbolic toolbox is also able to solve finding limits, e.g. >> clear, syms x a; >> limit( sin(a*x)/x, x, 0 ) ans = a
There are cases where the limit depends on the direction from which it is approached. Consider for instance tan(x) in the limit of x = π/2 [if you forgot the shape, try ezplot(’tan’)]. We can use MATLAB’s numeric engine, >> tan(pi/2), tan(pi/2+eps) ans = 1.6331e+16 ans = −6.2184e+15
13.6. Solving ordinary differential equations
103
which shows that a very small increment of the angle makes a huge difference, as expected. The symbolic engine finds the two correct solutions, >> limit( tan(x), x, pi/2 ) ans = NaN >> limit( tan(x), x, pi/2, 'left' ) ans = Inf >> limit( tan(x), x, pi/2, 'right' ) ans = −Inf
% That's a kind of warning
Exercise 13.8. Find the limit of (1 + a/x)x for x → ∞ (in Matlab: inf). The result may surprise you!
13.6
Solving ordinary differential equations
An ordinary differential equation can be solved symbolically with the command dsolve. >> syms f(x) a >> dsolve( diff(f) == a*f ) >> dsolve( diff(f,x) == a*f(x) ) ans = C1*exp(a*x)
The arbitrary constant C1 remains to be determined from the boundary conditions. For the ODE we solved numerically in the previous chapter, including the boundary condition, >> syms y(x) >> dsolve( diff(y) == x*yˆ2 + y, y(0) == 1 ) ans = −1/(x − 1)
Exercise 13.9. Solve the differential equation y ′′ (t) + 3y ′ (t) + 3y(t) = e−t with y(0) = y(1) = 0. Exercise 13.10. Solve the differential y ′′ (t) + 3y ′ (t) + 2y(t) = t with y(0) = 0, and y (1) (0) = 3. Hint: the second boundary condition requires an auxiliary function. The solution to a differential equation can be long and complicated, so it would be nice if one can plot the solution. Since the answer is symbolic expression, it takes a little manipulation before one can use plot. The ezplot command does work with symbolic expressions. >> syms f(x) >> g = dsolve( diff(f) == −4*f + x, f(0) == 1 ) g = x/4 + (17*exp(−4*x))/16 − 1/16 >> ezplot(g)
13.7. Summations
104
>> ezplot(g,[−3:3]) % user−supplied range >> g(x) = dsolve( diff(f) == −4*f + x, f(0) == 1 ) % Note the g(x): matlab does g(x) = % not automatically recognise the output as a function x/4 + (17*exp(−4*x))/16 − 1/16 x = [−3:.1:3],; plot(x,g(x));
Exercise 13.11. Plot the solution of the differential equation of the previous exercise. Exercise 13.12. Type the following commands and see what happens. >> >> >> >> >> >>
syms x y t S = xˆ2 + 3*x*y + yˆ2 − 10 ezplot(S) f = cos(2*t) g = sin(4*t) ezplot(f,g)
13.7
Summations
Matlab’s symbolic engine is also capable of doing symbolic summations. >> syms x i n >> s = symsum( xˆi, i, 0, n ) s = piecewise(x == 1, n + 1, x ∼= 1, (x*xˆn − 1)/(x − 1))
Here piecewise indicates that there are two answers, depending on the value of x: for x = 1 the summation equals s = n + 1, for x 6= 1 one has s = (xn+1 − 1)/(x − 1). On may even add up infinitely many terms, >> clear, syms x k; >> symsum( 1/kˆ2, k, 1, Inf) ans = piˆ2/6 >> f(x) = symsum( (−1)ˆk*xˆ(2*k+1) / factorial(2*k+1), k, 0, inf ) f(x) = sin(x)
Exercise P∞ 13.13. P k Solve k=1 1/k2 and ∞ k=0 x /k!. The results may surprise you!
13.8. Symbolic substitution
13.8
105
Symbolic substitution
Matlab also has a nice command for symbolic substitution: in expression one may replace old by new using the command subs(expression, old, new). For instance, >> syms x y z; >> z = xˆ2 * y; >> subs(z, x, 4) ans y + 16 >> subs(z,y,3) ans xˆ2 + 3 >> subs(z,x,yˆ2) ans yˆ4 + y >> z = subs(z, x, 4) z = y + 16 >> z = subs(z,y,3) z = 19
It is also allowed to make multiply substitutions at once by using a vector or matrix as the new object. For example >> syms x y; >> x = yˆ2; >> subs(x,y,[0 1 2 3 4 5 6]) ans = [ 0, 1, 4, 9, 16, 25, 36]
Exercise 13.14. Use subs to work out what x is as function of z when you know x = y + y 3 − 5 and y = z + z 3 .
Exercise 13.15. Symbolic differentiate the function x = y 5 + sin y + ln y and evaluate it for the points y = 4, 10, 20, 40.
Part B C++
– 106 –
Chapter 14 Introduction to C++
14.1
Objective of the course
The goal of this short course in C++ is not to become a perfect C++ programming guru. For this we refer to special courses and a broad range of expert literature – see below in section 26.1. The goal of this introduction to C++ is to better understand computer hardware and software, to perform basic tasks, operations, and programming within the framework of the programming language C++. We will first install on your computer an advanced integrated development environment (IDE) software, that will let you edit, compile, and run C++ programs. Then you will learn how to read simple C++ programs, how to write own code, and to get used to error-searching/debugging of code.
14.2
Installation of a C++ compiler/IDE
C++ is a compiled programming language: Before you can execute the algorithm that you have written, it has to be compiled into an executable. There are many commercial C++ compilers, for various operating systems. While many Unix-type operating systems, like modern Linux distributions and MacOS, have C++ compilers and debuggers embedded (g++ and gcc), this is not the case for a Windows operating system. We also recommend you to download an IDE, i.e., a smart editor that helps you to write and compile C++ files. They usually can be downloaded together with a compiler, so make sure you include the compiler if you are a Windows user. There are many freely available IDE’s (e.g. Netbeans, Orwell C++, Netbeans) that you can download for free (under the GNU General Public License). For academic users, we recommend CLion, which requires you to apply for a free license, but offers very good code analysis and debug tools, which allows you to avoid common programming mistakes.
– 107 –
14.3. A short history of C++
108
Follow the following steps to get started:
• Download from https://www.jetbrains.com/clion/ execute the setup file and follow the installation instructions. Select Evaluate for free (you can later apply for an academic license) • Ready to start. To create your first C++ program, click on New Project, then replace the directory name untitled with a sensible name, e.g. FirstProgram, then click Create. The file main.cpp should now appear on the screen, containing the following: #i n c l u d e i n t main ( ) { s t d : : cou t << ” H e l l o , World ! ” << s t d : : e n d l ; return 0; } You can now modify the file, and compile and run it. To do so, use the buttons at the top right of the screen:
The first button is called Build and compiles the program; the second-last button is called Run) and executes the program; you will see the output of the compilation and run at the bottom of the screen.
14.3
A short history of C++
C was developed in the 70’s by K. Thompson, B. Kernighan, and D. Ritchie, and was introduced together with the operating system UNIX. Today’s popular operating system LINUX is the free derivate of UNIX, and, like its ancestor, is based on C, i.e., the operating system is – in big parts – written in C. The original goal was a standardised language for the structured programming. However, the so-called ANSI-standard was only introduced as late as 1988 as ANSI-C. C++ can be seen as an extension of C, developed, propagated and introduced between 1983 and 1985 by B. Stroustrup. Besides the goal to develop a higher, object-oriented language, down-ward compatibility with C was desired. Therefore, C is to be seen as a fraction/part of C++. The ANSI Standard for C++ was fixed in June 1998. In the framework of this course, we will use C++ syntax whenever this is simpler than C, e.g. for I/O (input/output). The C++ language is being actively developed, and new standards have being published in 2003, 2011 and 2014. These new standards extended the language capabilities, while preserving backwards compatibility. In particular, the C++11 standard has introduced many new features that make it easier to create and manipulate datasets. You will learn many of these new features in this course.
14.4. Why use C++?
14.4
Why use C++?
Some reasons for the use of C++ are • it is free – both compiler and IDE’s are available under the GPL licence • it is system-independent – from micro-processors to super-computers • it is rather low level – close to the operating system • it is extendable, re-usable, and robust, ...
109
Chapter 15 Programming-style
This section briefly discusses some issues related to a good style of programming. Good style means that programs are simple and easy to read. It involves some rules like indentations that make the program also optically structured and, finally, it involves comments that describe in words what the program is doing. Note that a good style does not only help other people reading and understanding your program, it also will help you to understand your own program – after you have not looked at it for a while. Think not of the few 100 lines we will write in this course, think of several 10,000 lines of code that a programmer can write, during a thesis for example. In “real life” programmers do NOT spend most of the time programming; instead, they debug (search for errors) and update, change, optimise and re-use existing codes and code-fragments. For these tasks, a clean, proper, and consistent style is not only helpful, but absolutely necessary. This is – by the way – true for all programming languages, including MATLAB.
15.1
Comments (see also §16.1)
There are two things a program should do: First, it tells the computer what to do and, second, it also tells the (human) reader of the program what it does. A working program without comments is a time-bomb. Even the simplest ideas flowing into the program will be forgotten after some time ... and without comments, a program can not be re-used. Without comments, a program cannot be understood or changed so that either it has to be program anew, or a lot of time is spent re-understand the exciting program; both are a waste of time. In C++ there are two types of comments.
– 110 –
15.2. Clear style
111
The first, traditional comments begin with /* and end with */. They can enclose single characters or many lines and are most convenient for larger comments, or for making old code invisible to the compiler. /∗ Use comments t o make t h e r e a d e r under sta nd what your program do es . ∗/
Alternatively, you can write line-comment that begin with two forward-slashes // and end at the end of a line. It can start anywhere in the line and is thus convenient for commenting single commands. // Use l i n e comments t o comment co de s n i p p e t s , o r s i n g l e l i n e s o f co de .
As a suggestion, each program should have a comment block at the beginning, containing the most important information: • Header Name of program and what is it supposed to do. • Author Author and (e-mail) contact address • Date Date of creation. • How to use the program Describe the mode of usage. • Files (I/O) File format and of input files and output data-files • License/Restrictions Are there any restrictions to the use of this program? • Revisions Dates and type of changes performed. • Error management What happens when a program detects an error. • Other remarks ...
15.2
Clear style
A program should be readable like a thesis or a scientific paper. It should contain an introduction, like the header comment above, and it should be clearly separated in chapters, paragraphs, etc. with clear boundaries. Comments can be used as a way to optically separate paragraphs within the program.
Chapter 16 The basics
16.1
Language Elements
The first language element are comments. They do not affect the function of the program or the computer – they enhance the understanding of the program when read by another (human) user. A comment is everything between ’/*’ and ’*/’ or after ’//’. The second essential element is the data, i.e., constants and variables. These can be of different type: booleans, integers, doubles, characters, or self-defined data structures (classes). It is necessary to tell the computer which data is required for the program to work. This could be done anywhere in the program, however, this is neither efficient nor clean or clear programming. It is recommended to define data (only) at the beginning of a function/program. Exceptions to this rule will be discussed below. Other elements, like operators, control structures, and functions, are required to manipulate the data. Examples for operators are the assignment operator =, the basic arithmetic operations +, -, *, or /, and comparison operators (==, !=, >, <, >=, <=). However, there are many more, as summarised in table 16.1 and discussed in more detail later in §16.4. Examples for control structures are for, do and while-loops, situation dependent execution with if, else if, and else or switch, local scopes with begin and end brackets { and }, and many others as defined in the next subsections. Examples for functions are mathematical functions like sin, cos, or pow, but functions can also be user-defined, containing sequences of operations that are repeated many times. Use of functions makes the program shorter and better readable. In C++, the so-called main program is also a function – it marks the beginning of your program, and is always called main() (that means no other function can use this name). Begin and end of a function are marked by the curly brackets ‘{’ and ‘}’.
– 112 –
16.2. Hello World
113
Operator type Assignment Arithmetic operators Increment operators Relational operators Logical operators Bitwise Operators Compound assignment Other operators
Operators = +, -, *, /, % ++, -==, !=, >, <, >=, <= !, &&, || ~, &, |, ^, <<, >> +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |= sizeof(), (type), ? :, ,, ::, (), [], ., ->, *, &, . . .
Table 16.1: Examples of operators, sorted by type The next class of language elements are those used for the communication between the user and the computer, the so-called I/O (input/output) functions and operators. In C++, standardised libraries exist that contain the definitions of the I/O commands. The simplest way of I/O is output on the screen and input via the keyboard. The next way – especially when a lot of information has to be input into the program or is returned – is via data-files (for both input and output). Finally, there are organisational elements, that do not per-se belong to the programming language, but can be used for management of the program before compilation and execution, e.g., by the so-called pre-processor. This allows to shorten and clarify the program by just moving big, un-clear code-fragments out of the program, or by conditionally selecting alternative parts of the code.
16.2
Hello World
Your first program (CLion −→ Create Program) looks like this: #i n c l u d e i n t main ( ) { s t d : : cou t << ” H e l l o , World ! ” << s t d : : e n d l ; return 0; } • The first line includes a file, iostream, from the C++ standard library that provides definitions for input and output operations (I/O). Important for us, this library provides objects like std::cin and std::cout that can be used to read and write to the console.1 There is a whole set of C++ standard libraries that provide additional functionality to 1
std is a so-called namespace and is prepended to most functions that are included in the standard libraries. As many common functions are in the std name space, many programs include the line using namespace std which allows you to call the function without the std:: prefix.
16.3. data types, Variables, Constants
114
C++ programms2 . Including libraries is done at the beginning of the source file – outside the main() function. • int main(){...} is a function of type int, that is the program will return an integer value. Every program contains exactly one such function (there can be many more functions, but only one main function. The ()-brackets are used to denote that the program takes no input arguments. Note, C++ programs can take input arguments,, however, we delay the discussion of this to later. • The brackets {...} enclose the main-program, i.e. the commands, the main function main(...) consists of. In general, program blocks are enclosed by these curly brackets, and each begin-bracket { must be accompanied by an end-bracket }. • The next line is the hardest to understand, and we will leave the details for later. For now, it is important to know that this line passes the string "Hello, World!" to the console output, followed by an end-of-line character. • The main function ends with return 0;. Thus the main function, will return 0 to the operating system, indicating that the programm ran sucessfully (without errors). Returning any value other than zero tells the operating system that your program has failed. • Note that a new line is not the end of a command in C++. Instead, every command has to be ended by a semicolon ‘;’. In fact, C++ allows you to freely format your program using newlines, whitespaces and tab, except in comments and commands beginnning with #. The following programm would have been acceptable C++ code: #i n c l u d e i n t main ( ) { s t d : : cout<< <<s t d : : e n d l ; r e t u r n 0 ; }
” H e l l o , World ! ”
For readability, however, it is best to not use several commands within a single line in order to keep the program clean and readable. Since the semicolon has the function to separate two commands, it is not found at the end of program-blocks, that are already clearly terminated by the end-bracket of the pair {...}.
16.3
data types, Variables, Constants
16.3.1
Numbers
Computers process numbers (and also symbols) in binary representation. The binary system was developed by G.W. Leibniz when studying Chinese letters. Based on the binary representation, also octal (3 bits) or hexa-decimal (8 bits) representations are used in the computer. Example – if you really want to know: The integer 496 can be represented in different bases as follows (where the subscript indicates 2
If you click on iostream while holding the Ctrl button (Command on MacOS) in Clion, you can see the header file; these are written by hardcore programmers, so don’t be scared if you don’t (yet) understand the contents.
16.3. data types, Variables, Constants
115
the base, and superscipts are mathematical powers): 49610 = 4 · 102 + 9 · 101 + 6 · 100
= 1 · 28 + 1 · 27 + 1 · 26 + 1 · 25 + 1 · 24 + 0 · 23 + 0 · 22 + 0 · 21 + 0 · 20
= 1111100002
= 7 · 82 + 6 · 81 + 0 · 80 = 7608 = 0760 2
(octadecimal numbers have 0 prepended in C++)
1
= 1 · 16 + 15 · 16 + 0 · 160
= 1F 016 = 0x1F0
(octadecimal numbers have 0x prepended in C++)
(16.1)
Try this for yourself by running the following program: #i n c l u d e i n t main ( ) { int n = 496; s t d : : cou t << s t d : : dec << n << s t d : : e n d l ; s t d : : cou t << s t d : : o c t << n << s t d : : e n d l ; s t d : : cou t << s t d : : hex << n << s t d : : e n d l ; return 0; } Numbers x in floating-point representation (0.496e+03) are transformed to fixed-point notation using the formula x = mbe
(16.2)
with the “mantissa” m (here 496), the basis b (b = 10 could be also b = 2, 8, 10, 16), and the exponent e (here 3). The in-fact implementation of floating-point numbers is machine/processordependent and will not be discussed here.
16.3.2
Basic data types and their declaration
The built-in, primitive data types in C++ are: bool, char, int, float, and double. Historically processors were optimised to deal with these data types – however, the development of processors has progressed so much that also other data types are efficiently treated. Usually, a compiler can optimise a code such that a user does not feel anymore the difference between different types of data. The type bool is a logical data-type that can be used, e.g. to deal with the result of a logical comparison using logical operators, see Sec. (16.4). It can only have two values: true or false. Its freely transformable to data-type int, where true corresponds to 1 and false to 0. This transformation was introduced for compatibility reasons, to old programs where instead of bool just int’s were used. Some simple declarations are: bool t e s t ;
// d e c l a r e t e s t with out i n i t i a l i s i n g i t s v a l u e
16.3. data types, Variables, Constants
116
t e s t = (0 < 5 ) ; // t e s t i s s e t to r e s u l t o f com p ar is on ( t r u e ) i n t i ( t e s t ) ; // i i s d e c l a r e d and s e t to v a l u e o f t e s t ( t r u e ) i n t j =0; // j i s d e c l a r e d and s e t to f a l s e Initialisation/Construction of a variable can be performed as type variable = type constant or equivalently as type variable(type constant). For experts: The symbol ’=’ does not denote the assignment operator if the variable was just declared (created); instead, the copy-operator () is called. The type int is recognised by the compiler (i.e. the compiler-programmer) as most appropriate for dealing with integer numbers. Its size is not fixed in the standard, but usually 4 bytes (32 bit). However, with help of the operator sizeof, one can determine the size of a type or variable in bytes. Different computers also support other integer data types, e.g., 2, 8, or 16 bytes. These are defined using short and long or (not ANSI conform) long long. In addition there is the unsigned type for storing non-negative integers (the longer form of declaration short int, long int, unsigned int is not required). short i = 0; int j , k , l ; l o n g m=0, n=1; unsigned u ; s t d : : cou t << ” S i z e << ” S i z e << ” S i z e s t d : : cou t << ” S i z e
of of of of
v a r i a b l e i : ” << s i z e o f ( i ) v a r i a b l e k : ” << s i z e o f ( k ) v a r i a b l e m: ” << s i z e o f (m) << s t d : : e n d l ; typ e b o o l : ” << s i z e o f ( b o o l ) << s t d : : e n d l ;
Note that an integer variable always has an integer value – even if one assigns a real (floatingpoint) value to it. int i = 38.5674 , j = 10; // ATTENTION ! s t d : : cou t << i << ” ” << i / j << s t d : : e n d l ; // ou tp u t i s 38 3 The data types float and double are the single- and double-precision floating point data types that are implemented optimally in the processor. The type long double can be used to get quad-precision (if supported). The in-fact representation of floating-point numbers is hardware dependent, e.g., in 1998 at least the double-precision basic operations were hardware implemented. With the current 64-bit processors, more and faster operations with larger numbers are possible. Type float should only be used if memory is a problem, since for processor operations, float often has to be modified to double anyway. C++ does not specify how variables are represented in memory and the use of memory is not specified per type either. However, at least the relations: 1 = sizeof(char) = sizeof(bool) ≤ sizeof(short) ≤ sizeof(int) = sizeof(unsigned) ≤ sizeof(long) and sizeof(float) ≤ sizeof(double) ≤ sizeof(long double) are always true.
16.3. data types, Variables, Constants
117
In general, on UNIX-machines, int-variables are 4, short 2, and char 1 byte long. Doubleprecision double requires 8, float only 4 bytes. The values used are different from machine to machine, but also can be different from compiler to compiler. One can check the range of the basic data type using the numeric_limits library: #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( ) { co ut << ”Minimum co ut << ”Maximum co ut << ”Minimum co ut << ”Maximum }
i n t : ” << i n t : ” << do uble : ” do uble : ”
n u m e r i c l i m i t s : : min ( ) << e n d l ; n u m e r i c l i m i t s : :max ( ) << e n d l ; << n u m e r i c l i m i t s <double > : : min ( ) << e n d l ; << n u m e r i c l i m i t s <double > : :max ( ) << e n d l ;
In the following example, different data types are declared: #i n c l u d e <s t r i n g > i n t main ( ) { cha r c1 = ' x ' ; cha r c2 [ ] = ” h e l l o ” ;
// one c h a r a c t e r : ' x ' // t e x t a r r a y with 5 c h a r a c t e r s // ( no te : l e n g t h i s 6 due t o added ' \ 0 ' ) std : : s t r i n g s t r ( ” h e l l o ” ) ; // t h e C++ way , a r b i t r a r y l e n g t h s t r i n g s // ( no te : l e n g t h i s 5 − no added ' \ 0 ' ) cha r c3 = ' \n ' ; // t h e new−l i n e c h a r a c t e r int i var ; // i n t e g e r v a r i a b l e with name i v a r long i n t il var = 1; // l o n g c o n s t a n t long i n t j l v a r = 1L ; // a n o t h e r l o n g c o n s t a n t short is var ; // s h o r t i n t e g e r v a r i a b l e ( i n t per d e f a u l t ) do uble d var = 3 4 . 2 ; // r e a l number 3 4 . 2 with do uble p r e c i s i o n
}
Note that for char variables single characters have to be enclosed by apostrophes, e.g. 'x', whereas arrays of characters must be enclosed by a double apostrophe, e.g. "hello". Above, the variables c1 and c3 both have length unity (1), whereas the chain "hello" is accessible in the C-style array c2 and has length 6, since during its declaration, automatically, a symbol '\0' is added. (Try the definition char c2 = 'hello'; that will lead to an error.) More flexible is the C++ method to use string, which do not need the terminator '\0'. Note that for strings, the standard-library string must be included, see above. For a computer there are three types of single quotes: left quotes ‘, right quotes ’ and straight quotes '. Characters must be enclosed by two straight quotes, or your code will not compile. Some operating systems try and be clever and insert ‘ the first time you ask for a quote and ’ the second time. If you get this problem turn off sticky keys on your operating system and it should disappear. Declaration of variables is not limited to the beginning of a block, but can be done everywhere at first occurrence of a variable – be it clear, useful, and efficient or not.
16.3. data types, Variables, Constants
118
Important and useful is the declaration within a for(;;) loop, as discussed in more detail later: d ou b le a ; c i n >> a ; // i n p u t a v i a keyboard int i trunc = a ; // throw away th e f r a c t i o n a l p a r t f o r ( i n t i =0; i < i t r u n c ; i++ ) { // . . . } In the above program, the variable i does not exist outside of the for(;;) loop, neither before nor after. Summary (i) Declarations can be located at arbitrary position in the program (ii) Initialisation with () or = operator (iii) sizeof(type) can be used if the size of a type must be known, e.g., for portability between different computers/architectures.
16.3.3
Type conversion
It is possible it change one variable into another type i n t p=2, q=3; d ou b le r=p /( d ou b le ) q ; Here this is necessary to make sure rounding does not take place in the answer of r. Two very useful ones are for converting char arrays to double and integers; the commands are atof and atoi respectively. const const int i float
ch ar ∗ s t r i n t = ” 777 ” ; ch ar ∗ s t r f l o a t = ” 3 3 3 . 3 ” ; = atoi ( s tr in t ) ; f = atof ( s t r f l o a t ) ;
Please note in C++ this can be done using stringstream’s and this method is recommended nowadays, see §16.3.6.
16.3.4
Variable-attributes
Besides the attributes short or long integer variables can be also modified by signed and unsigned, that allow to use integers (positive or negative) or exclusively positive integers, respectively. The int can be dropped here.
16.3. data types, Variables, Constants
119
Exercise 16.1. Write a problem to find out the size of variables of different types on your computer.
16.3.5
string type
String objects are a special type of container, specifically designed to operate with sequences of characters. Each character of the string can be access using the [] operator i.e. string a ; a=” H e l l o ” ; string b; b=a [ 2 ] ; cou t << b <<e n d l ; would write out the letter ‘l’ , recall c++ arrays start numbering at 0. Additional with the + operator can be used to concatenate two strings together; for example string a ,b, c ; a=” H e l l o ” ; b=”World” ; c=a+b ; cou t << c << e n d l ; would produce ‘Hello World’. Note: The function c_str() returns a const pointer to a regular C string, identical to the current string. The returned string is null-terminated. This is often required because a lot of routies require C strings not C++ strings to be passed to them.
16.3.6
String stream
stringstream’s provide an interface to manipulate strings as if they were input/output streams. They are declared in the header called sstream, as you would expect from the other stream names, but the type is called stringstream. This is described here, after string for ease of finding, but iostreams are described in more detail in chapter 23, so please refer to this section for a more detailed explanation of streams. Below is a small example code that creates a filename by passing information into a stringstream and re-extract the string at the end. #i n c l u d e <s s tr eam> #i n c l u d e #i n c l u d e
16.3. data types, Variables, Constants
120
u s i n g namespace s t d ; i n t main ( ) { stringstream file name ; s t r i n g s t r e a m problem name ( ” my problem ” ) ; ofstream s c r i p t f i l e ; f i l e n a m e << problem name . s t r ( ) <<” . d i s p ” ; s c r i p t f i l e . open ( ( f i l e n a m e . s t r ( ) ) . c s t r ( ) ) ; // . . s c r i p t f i l e . close ( ); return 0; } The key commands are << which adds data to the stringstream this can be any type for which the << operator is defined. The .str() method return a traditional C++ string, see section 16.3.5 were .c_str() is also described. The nice thing about stringstreams is they automatically deal with type conversion. For example the code below will convert a string to int via a stringstream. #i n c l u d e #i n c l u d e <s s tr eam> u s i n g namespace s t d ; i n t main ( ) { int a ; s t r i n g s = ” 456 ” ; istringstream sin ( s ); s i n >> a ; cou t << a << e n d l ; return 0; }
16.3.7
Life-time and position in memory
auto If there is no further declaration, variables are automatic. These variables have a finite lifetime, or scope. This means they are assigned to memory as soon as the program reaches the line where they are declared. As soon as the program leaves the scope where they are declared, the memory is freed again. (The scope is, in general, the inner-most enclosing pair of brackets, or like in the case of a for(;;) loop, the end of this object.) For experts: Variables of this type are usually assigned by the compiler to the so-called stack memory. The value of such a variable is random (!), if not explicitly assigned or initialised. Thus make sure to initialise your variables! Aside: stacks, heaps, etc.
16.3. data types, Variables, Constants
121
In computer science, a stack is a last in, first out (LIFO) abstract data type and data structure. A stack can have any abstract data type as an element, but is characterised by only two fundamental operations, the push and the pop. The push operation adds to the top of the list, hiding any items already on the stack, or initialising the stack if it is empty. The pop operation removes an item from the top of the list, and returns this value to the caller. A pop either reveals previously concealed items, or results in an empty list. (See Wikipedia for further reading). A queue is a particular kind of collection in which the entities in the collection are kept in order and the principal (or only) operations on the collection are the addition of entities to the rear terminal position and removal of entities from the front terminal position. This makes the queue a First-In-First-Out (FIFO) data structure. (See Wikipedia for further reading). In computer science, a heap is a specialised tree-based data structure that satisfies the heap property: if B is a child node of A, then key(A) ≤ key(B). This implies that an element with the greatest key is always in the root node, and so such a heap is sometimes called a max-heap. (Alternatively, if the comparison is reversed, the smallest element is always in the root node, which results in a min-heap.) The several variants of heaps are the prototypical most efficient implementations of the abstract data type priority queues. Priority queues are useful in many applications. In particular, heaps are crucial in several efficient graph algorithms. (See Wikipedia for further reading).
static The keyword static makes a variable exist during the whole duration of the program. For experts: Such variables are saved on the heap-memory. If not initialised otherwise, they get the value 0 (zero). A static variable inside a function has thus the value 0, if the function is called for the first time, and keep this (or another assigned value) between subsequent calls to this function. In contrast, an automatic variable is every time newly created and initialised. The following function counts how often it was called and returns this value. int f count cal ls () { s t a t i c i n t count ; r e t u r n ++count ;
// 0 at f i r s t f u n c t i o n c a l l // i n c r e m e n t b e f o r e u s e as r e t u r n v a l u e // ( i . e . r e t u r n s one on th e f i r s t c a l l )
} const Variables that are declared const, can only be assigned a value at initialisation and not anymore thereafter. This is used to define constants within a namespace that – by the compiler – can be optimised such that their use costs less time than using variables. Thus, if variables can be defined as constants, this might lead to a faster program execution. const int Size = 100; c o n s t d ou b le Pi = 3.1415926; // S e l f −d e f i n e d v a l u e o f PI // When i n c l u d i n g cmath one can u s e th e p r e d e f i n e d c o n s t a n t M PI
16.3.8
Fields
Fields are used to combine variables of the same type in a connected range of memory. For experts: Access to variables can be faster if they are in such a connected range of memory and,
16.3. data types, Variables, Constants
122
on the other hand, using fields also can make a program shorter and more clear. Access to the elements of a field is achieved by an integer index. A linear field (with one index) can be seen as a vector, while a field with two indices represents a matrix. Mathematical formulas with indices can often be represented in a program using fields. A field is declared in C++ by adding brackets [] to the variable name. At the same time, this operator is also used to access the elements of the field, see below. In C++ fields always start with the index 0, so that the last valid index is the length of the field reduced by 1. Multi-dimensional fields are declared by multiple (not enfolded) pairs of brackets, see below. Such fields receive – at declaration – a fixed size. Thus, the argument in brackets [], must be either a number, a const variable, or a well-defined variable with a known value for the compiler (at compilation time). #i n c l u d e <s t r i n g > i n t main ( ) { // a r r a y o f 20 i n t ' s int a [ 2 0 ] ; // i n i t i a l i s a t i o n o f f i e l d a −− ERROR! f o r ( i n t i =0; i <= 2 0 ; i++ ) a[ i ] = i ; // i n i t i a l i s a t i o n o f f i e l d a f o r ( i n t i =0; i < 2 0 ; i++ ) a[ i ] = i ; // a r r a y o f t h r e e s t r i n g s , i n i t i a l i s e d to some v a l u e s : std : : s t r i n g s t r a 2 [ ] = { ” Katia ” , ” H o l g e r ” , ” S t e f a n ” } ; // two d i m e n s i o n a l a r r a y o f 20 x30 e l e m e n t s o f i n t typ e int ia [ 2 0 ] [ 3 0 ] ; // i n i t i a l i z a t i o n o f f i e l d i a f o r ( i n t i =0; i < 2 0 ; i++ ) f o r ( i n t j =0; j < 3 0 ; j++ ) ia [ i ] [ j ] = i ∗ j ; return 0; } Later, we will see that fields and pointers are closely related. The use of pointers allows to define “dynamic” fields of a size that is determined during run-time, e.g., following a user-decision and -input. C++ supports containers that can dynamically allocate memory and allows simple manipulation of fields, such as vector or valarray. The C++ vector-container is discussed in more detail 22.5 . Nowadays the use of C++ vector over fields is often recommended; however, non careful use can lead to slow code.
16.4. Operators
16.4
123
Operators
Operators allow us to make a program readable. Sometimes, unfortunately, they also make a program un-readable, cryptic and unclear. A term like 3 * z + 5 is easily understandable, whereas the term plus(mult(3,z),5) that is expressed using functions is much less clear. There exist unary, binary, and ternary operators. Binary operators like the multiplicationand addition-operators, have two arguments, while unary operators, like the address-operator & require only one. Finally, ternary operators take three arguments, the discussion of these is delayed until § 17.2. Table 16.1 gives an overview of all operators in C++. We have already been using assignment and arithmetic operator and next we will discuss these in more detail.
16.4.1
Arithmetic operators
The arithmetic operators are +, -, *, / and %. The Operator % (modulo) forms the integer rest of the division of the left with the right operand (both integer). If both are positive, the result is positive and strictly smaller than the right operand. For one or two negative operands, the result depends on implementation. Combining the above operators with the ’=’ allows to repeat the left operand, as for example: int i i i i
i =3, j =7; = 3 + j % i; += 3 ∗ 4 + j ; /= 5 ; /= 5 ;
// // // // //
initialise i = 3 + ( j mod i ) , i = i + (3 ∗ 4 + j ) , integer division , i integer division , i
i i is is
i s s e t to 4 i s s e t to 23 now 4 now 0 !
The type that is returned by an operator expression depends on the type of the operand. If both operands are type T, also the result is type T. For different operand-types the “better” type wins; one operand is first transformed to the “better” type, then the operation is carried out. C++ has the following “type promotions”: bool -> char -> short -> int -> long -> float -> double -> long double signed -> unsigned (!) These rule of type-transformation are also valid for the following operators. The unary operators ++ and -- exist in postfix and prefix-form, and they lead to an increment or decrement by one, respectively. In the postfix form, the value of the operand before the operation is returned, whereas in the pre-fix form, the value after is returned. i n t i =5, j ;
16.4. Operators
124
j = i ++; // j i s 5 now ( i b e f o r e i n c r e m e n t ) i i s i n c r e m e n t e d to 6 d ou b le a [ 2 0 ] ; i=j ; cou t << a[++ j ] << a [ j ++]; cou t << a [ i ++] << a[++ i ] ;
// i=j =5 // p r i n t s a [ 6 ] tw ice , j i s now 7 // p r i n t s a [ 5 ] and a [ 7 ] , i i s now 7
// j++ = i ; // ERROR: can n ot a s s i g n to a temporary // i = ( j ++)++; // ERROR: can n ot ap p ly ++ to a temporary
16.4.2
Assignment and increment operators expression x += y x -= y x *= y x /= y x %= y ++x --x
short for: x = x + y x = x - y x = x * y x = x / y x = x % y x = x + 1 x = x - 1
Table 16.2: Additional assignment operators, and the long form they replace
16.4.3
Comparison and logical operators
For operations between two integral datatypes, there exist bitwise, logical, and shift operators. (C++ also provides keywords for these). These operators are summarised in table 16.3, and they also can be combined with the =. | & ^ << >> ~ |= &= ^= <<= >>=
bitor bitand xor
compl or_eq and_eq xor_eq
bitwise OR bitwise AND bitwise XOR left-shift, n-times right-shift, n-times complement, bitwise NOT, unary bitwise OR, to-left assignment bitwise AND, with assignment bitwise XOR, with assignment left-shift, n-times with assignment right-shift, n-times with assignment
Table 16.3: Bit-manipulation-operators
The logical operators are && (and) and || (or) and the negation ! (not) . The operators && and || have the special property that the evaluation of this expression is terminated already if the
16.4. Operators
125
result is clear (so-called sequencing). This property is also shared by the comma-Operator , – that sometimes is used to construct complicated for-loops. Its value is the same as the value of the right expression. i n t a =5; i n t b=10; i n t c =5; bool i s i t t r u e ; i s i t t r u e =(( a==c ) && ( a!=b ) ) // This i s t r u e i s i t t r u e =((a>b ) | | ( b>c ) ) // This i s a l s o t r u e The (arithmetic) comparison-operators are ==, !=, <, <=, > and >=. The value of a logical operation and the result of a comparison in C++ are of type bool, i.e. either true or false.
16.4.4
Further operators
Here all other operators except the ternary operator, ?:, which is used to select alternative expressions of the same type, will be discussed. See sec. 17.2 for this operator. int i ; cou t << ( i > 0) ? i : 0 ;
// n e v e r p r i n t s a n e g a t i v e number
The operator () leads to a function-call, [] is the index-operator for fields and pointers, a point '.' allows to select an element from a structure and -> is equivalent when a pointer to a structure is given. c l a s s Person { public : s t r i n g name ; i n t age ; }; void f (){ Person p; Person ∗ p p = &p ; p . age = 25; p p−>age = 2 5 ; // e q u i v a l e n t } The unary operators * and & are used to find the value of the memory location where a pointer points at, and to find an address of an arbitrary variable (see sec. 20).
16.5. Summary
126
Operator-expressions are (like in C) treated according to their priority and associativity, see table 16.4. P. 1 2
3
4 5 6 7 8 9 10 11 12 13 14 15
16 17
Operator :: ++ -() [] . -> ++ -+ ? ! ~ (type) * & sizeof new, new[] delete, delete[] .* ->* * / % + ? << >> < <= > >= == != & ^ | && || ?: = += ?= *= /= %= <<= >>= &= ^= |= throw ,
Description Scope resolution Suffix/postfix increment and decrement Function call Array subscripting Element selection by reference Element selection through pointer Prefix increment and decrement Unary plus and minus Logical NOT and bitwise NOT Type cast Value-of (dereference) Address-of Size-of Dynamic memory allocation Dynamic memory deallocation Pointer to member Multiplication, division, and remainder Addition and subtraction Bitwise left shift and right shift For relational operators < and ≤ respectively For relational operators > and ≥ respectively For relational = and 6= respectively Bitwise AND Bitwise XOR (exclusive or) Bitwise OR (inclusive or) Logical AND Logical OR Ternary conditional Direct ass. (provided by default for C++ classes) Assignment by sum and difference Assignment by product, quotient, and remainder Assignment by bitwise left shift and right shift Assignment by bitwise AND, XOR, and OR Throw operator (for exceptions) Comma
Associativity Left-to-right
Right-to-left
Left-to-right
Right-to-left
Left-to-right
Table 16.4: Precedence (P.) and associativity of C++ operators. Operators are listed top to bottom, in descending precedence.
16.5
Summary
So far we have introduced the basic element of a program: variables, and discussed the many different types that are available. Also a few other commands have been used with out explanation, (but you can probably work out what they do) like cout, cin and for.
16.5. Summary
127
In the rest of this part, we will cover how to make decisions in a program, repeat sections of program, interact with the users and how to store data in a permanent way. Exercise 16.2. Explain what each line of the following code does i.e. add the comments #i n c l u d e u s i n g namespace s t d ; i n t main ( ) { i n t n , m; cou t << ” Enter two i n t e g e r s : \n” ; c i n >> n >> m; i n t sum=m+n ; cou t << ”Sum o f th e two i n t e g e r s i s ” << sum << e n d l ; return 0; }
Exercise 16.3. Modify the program to ask for three numbers Exercise 16.4. Modify your program to ask for both a person first name and surname. Get the program to output the persons initials, along with the sum of the three numbers they give.
Chapter 17 Decision structures
For implementing algorithms into a certain programming language, this language has to provide certain control-structures that allow repeated or conditional execution of parts of the program. In C (and C++) the most-used control strucures are the if-statement for the conditional execution, as well as the switch()...case:-statement, that jumps to one of many blocks of commands, based on the value of a certain variable. Finally, there is the command goto, that sometimes can be used to escape from (deeply nested) loops, see §18. (Actually I would not recommend ever using a goto, deaply nested loops can be exited by making the outer loop a function and using the return command, see §19).
17.1
The if-command
The if-command is used to execute parts of the program only under certain conditions. This command can be (but does not have to be) complemented by an else-statement, that is visited/exectuted in case the condition in the if-command is false. The else-part can consist of arbitrarily many else if and one else. As well if, else if, and else-branches can be single lines (terminated by a semicolon) or blocks, enclosed in curly brackets {}. An else-block always relates to the previous, actual if-command, i.e., also if it is part of an else if. In the following example, the second if-command is a statement by its own, outside the else-part of the first if. #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( ) {
– 128 –
17.2. The ternary ?: operator
129
// s o l u t i o n o f q u a d r a t i c e q u a t i o n s
xˆ2 + p x + q = 0
d ou b le p = 2. , q = 3 . ; // or o t h e r v a l u e s d ou b le s o l 1 , s o l 2 ; d ou b le r o o t a r g = 0 . 2 5 ∗ p∗p − q ; // c a l c u l a t e th e argument f o r th e r o o t i f ( root arg > 0. ) { // b e g i n o f i f −b l o c k sol1 = 0.5∗ p + sqrt ( root arg ) ; sol2 = 0.5∗ p − sqrt ( root arg ) ; } // end i f −b l o c k else i f ( root arg < 0. ) // ' e r r o r ' c o n d i t i o n , ' e l s e ' p a r t cou t << ”no r e a l s o l u t i o n e x i s t s ” << e n d l ; else // r e f e r s to l a s t i f ( r o o t a r g < 0 . ) sol1 = sol2 = 0.5 ∗ p ; // a s s i g n m e n t from r i g h t to l e f t cou t << ” S o l u t i o n s 1 , 2 : ” << s o l 1 << ' ' << s o l 2 << e n d l ; i f ( sol1 > 0. ) // ok , e l s e branch m i s s i n g cou t << ” graph c u t s p o s i t i v e x−a x i s ” ; return 0; }
17.2
The ternary ?: operator
For completeness, also the ternary ?: operator is treated here. Ternary means that this operator requires three arguments and is used to conditionally evaluate parts of expressions. i n l i n e i n t abs ( i n t number ) { // compute a b s o l u t e v a l u e r e t u r n number > 0 ? number : −number ; // E q u i v a l e n t form with b r a c k e t s // r e t u r n ( number > 0) ? ( number ) : (−number ) ; } Is the term before the question-mark true, then the term before the colon is examined. Otherwise, the term after the colon will be used. The two alternatives must be of the same type. Note that here, the use of brackets is recommended – partly because the ternary operator is of low priority and also because the terms that belong together should be made clear. int i1 int i2 int i3
= 3 > 4 ? 0 : 1; = 3 ∗ ( 3 > 4 ? 0 : 1 ); = 3 ∗ 3 > 4 ? 0 : 1;
// // // //
i1 i2 i3
is 1 is 3 i s 0 , s i n ce ∗ binds s t r o n g e r than >
17.3. switch-command
130
This operator always can be avoided by using an if-command, however, it could be more clear or at least shorter in some situations. In any case it is a possibility to write un-readable code and therefore should be used sparsely. (As final remark, the ternary operator is also embedded in the graphics program gnuplot.)
17.3
switch-command
A command related to the if and the goto commands is the switch-command. Dependent on the value of an integer variable, several case-blocks are visited. This construct is often used when there is a larger number of possible alternatives to be chosen from. In principle, a switch can always be replaced by if...else if-constructs, but often the switch is more clear and helps understanding and structuring the program. ch ar c ; c i n >> c ; switch ( c ) { c a s e ' a ' : cou t << b r eak ; c a s e ' b ' : cou t << c a s e ' c ' : cou t << b r eak ; d e f a u l t : cou t << b r eak ; }
// b e g i n c a s e b l o c k ” h e l l o world ! ” ; ”HELLO ” ; ”WORLD! ” ;
// f a l l t h r o u g h in ten d ed , comment m i s s i n g b r ea
”unknown i n p u t ” ; // not n e c e s s a r y , but good s t y l e // end c a s e b l o c k
The above program-segment returns in small letters "hello world!" if the letter 'a' is typed. In case c the word WORLD! is printed, but in case b the full sequence HELLO WORLD!. This strange behaviour comes from the missing break in the block b. This behaviour, namely that a execution is performed until a break, is called (“fallthrough”). Since this is often not desired, using this option required a comment whenever a break is missing. The default-label ist optional and is visited if none of the other labels is valid in the case-list.
Exercises Exercise 17.1. Modify the program from Exercise 15.4, so that it asks the users if he/she wants to enter 2 or 3 numbers. Read in the correct number of inputs and compute the sum. Exercise 17.2. Write a program that reads in a date in the format dd/mm/yyyy format and prints out 12th of March 2010 etc...
Chapter 18 Loop control structures
Often you want to repeat sections of a program, the most common way is using for-loops. Alternatively, the rejecting while()- and the accepting do{...}while()-loops exist.
18.1
(do) while-loops
Loops that are constructed using while are executed until the condition in the condition part of the loop is not true anymore. Is the condition already false at first occurence of the while-loop, the loop will not be executed at all. ch ar c =0; w h i l e ( c != ' y ' && c != ' n ' ) c i n >> c ;
// ' l o o p i n i t i a l i s a t i o n ' // f i r s t time c==0, s o we e n t e r th e l o o p // can a l s o be a b l o c k { }
The symbol/character variable has to be initialised such that the loop is entered. In such cases, the do ... while(...) loop might be more intuitive. ch ar c ; do { c i n >> c ; } w h i l e ( c != ' y ' && c != ' n ' ) ;
– 131 –
18.2. for-loops
18.2
132
for-loops
When working with fields, one often needs loops that access all elements of a field, one by one. One can program this with while: const int Size = 20; // . . int a [ Size ] ; // . . i n t i =0; while ( i < Size ) { a[ i ] = i ; i ++; }
// l o o p i n i t i a l i s a t i o n // l o o p c o n d i t i o n , r e j e c t i n g i f f a l s e
// l o o p c o n t r o l , p er f or m ed a f t e r each p a s s
A shorter alternative used the for(;;) loop. The following is almost equivalent to the above, but shorter by avoiding the line with i, and more clear, since the begin, end, and stepsize of the loop are defined at its start. int a [ 2 0 ] ; // . . f o r ( i n t i =0; i < 2 0 ; i++ ) // work on e l e m e n t s 0 . . 19 a[ i ] = i ; There are two advantages: First, the loop-beginning, -ending, and stepping is nicely combined in one line and, second, the variable i is only defined within the loop and not used (and not needed) outside.
18.3
break and continue
In order to exit a single, not-nested for or while loop, one can use the break command. The loop is terminated and the program continues directly after the loop. Thus break can be used to terminate loops under certain conditions, earlier than the loop implies, or it can be used to exit “endless” loops. // copy i n p u t to ou tp u t while ( true ) { ch ar c ; c i n >> c ; i f ( c i n . f a i l ( ) ) b r eak ; cou t << c ; }
// end o f i n p u t or s om eth in g wrong
18.3. break and continue
133
The command continue terminates the processing of the present block and continues, dependent on the type of the loop, at the corresponding control-command (for(;;)), or ((do{}) while()). #i n c l u d e d ou b le a [ 2 0 ] ; // . . . d ou b le s u m s q r t = 0 . ; f o r ( i n t i =0; i < 2 0 ; i++ ) { i f ( a [ i ] < 0. ) continue ; s u m s q r t += s q r t ( a [ i ] ) ; }
// f o r s q r t ( ) f u n c t i o n
// work on n ext elem en t
Note again that continue and break only exit the innermost loop-block and cannot be used to exit nested loops.
Exercises Exercise 18.1. Write a code which reads in N numbers and computes their sum. Exercise 18.2. Write a program to compute the squares of all integers between two numbers. Exercise 18.3. Write a program that computes the factorial of an inputed number N . Recall the factorial of N = N ∗ (N − 1) ∗ (N − 2) ∗ ... ∗ 1.
Chapter 19 Functions and Operators
Longer programs usually contain parts or blocks that are repeated a certain (large) number of times. These parts can then be defined elsewehere (as a function) and within the program are replaced by a short-cut or place-holder, i.e., the name of the function. It is wise to give the function a name that already implies its function. A function (also called procedure or subroutine in other languages), has input and output variables/parameters. In the simplest case the transfer of input-parameters is done as argument, and the output as a return-value. C++ enforces that the types of input and output are specified. In the following example, the function power computes from a double base value and an integer number exponent a new number in double precision that is returned to the calling function/program. The name already implies the algorithm used here. // r a i s e ' b as e ' to th e power ' exponent ' , with exponent b e i n g i n t e g e r , // b as e b e i n g d ou b le ; a c c e p t a l s o n e g a t i v e exp on en ts and ch eck . . . d ou b le power ( d ou b le base , i n t exponent ){ d ou b le r e s u l t = 1 . ; // w i l l m u l t i p l y t h i s b as e ' exponent ' t i m e s bool n eg exp = f a l s e ; i f ( exponent < 0 ) // f o r n e g a t i v e exp on en ts we u s e a s i n g l e { // d i v i s i o n at th e end o f th e f u n c t i o n n eg exp = t r u e ; exponent = −exponent ; } f o r ( i n t i =0; i < exponent ; i++ ) r e s u l t ∗= b as e ; // s u c c e s s i v e m u l t i p l i c a t i o n i f ( n eg exp ) // have to t a k e th e i n v e r s e r es u lt = 1./ r es u lt ;
– 134 –
135
return r e s u l t ;
// r e t u r n th e r e s u l t to th e c a l l i n g program
} Exercise 19.1. Search for the explanation of Flow-Chart in, e.g., Wikipedia, and plot the Flow-Chart of the Power-Function. Note that C++ already has a function pow that is described by double pow(double base, double exponent), only different in the type of the exponent. The names of the arguments are free to be chosen. Inside the function block these names are to be used. Note that like for loops, there is no semicolon after the function. The keyword return terminates the function at the specified position, moves the value of the variable specified after it on the stack, and returns to the calling program. In the case above, the expression consists only of a single variable result. Round brackets are not required here. A subroutine can contain several return keywords at different places in the function block. This can be a useful tool to deal with problems/errors. Hence the return command can be used to exit deeply nested for loop to forcing the exit of the whole function. Finally, one has to define or declare a function before it can be used in the program. This declaration is essentially the first line of the function (with semicolon). This so-called prototype tells the compiler the name of the function and the types of it and its arguments. Actually, if you careful about the order you do not need to prototype functions, but you must place the full function definition before the first call (use) of the function. This is often tricky to keep track of and prototyping is recommended. d ou b le power ( d ou b le base , i n t exponent ) ; At first definition, the command block is replaced by the single semicolon. Note that the type is required, but the name of the arguments in the function is not needed here. However, a clear program specifies variables that tell something about their purpose. Declarations can (in principle) be repeated arbitrarily often in a program – they are a promise to the compiler that the function will be defined later. Unlike variables, functions are always global – it is not allowed to define them inside a block with limited existence. Actually function and varibles can be wrapped together in a very neat package, called a class, see §?? for more details, solving this global scope problem. A program that reads a number from the keyboard and then uses the function power to finally write the result could look like this. #i n c l u d e u s i n g namespace s t d ; d ou b le power ( d ou b le base , i n t exponent ) ;
// d e c l a r a t i o n o f ' power '
19.1. Transfer of arguments
i n t main ( ) { d ou b le i n ; c i n >> i n ;
136
// d e f i n i t i o n o f main
// r ead v a l u e from keyboard
cou t << ”−3rd to 3 rd power o f ” << i n << ” : ” ; f o r ( i n t i= −3; i <= 3 ; i++ ){ cou t << power ( in , i ) << ” ” ; // c a l l power and u s e r e t u r n v a l u e } cou t << ” \n” ; return 0;
// r e t u r n to o p e r a t i n g system
} d ou b le power ( d ou b le base , i n t exponent ) { d ou b le r e s u l t = 1 . ; // . . . program t e x t as above
// d e f i n i t i o n o f power
return r e s u l t ; }
19.1
Transfer of arguments
The transfer of arguments to a function takes place “by value”, i.e., before the function is called, the arguments are copied and the function uses these copies. This way, the variables that contain the values that are transferred to the function can not be changed. If this is desired, e.g., because one return value is not enough and many variables are to be changed in a function, then one either use pointers, as disucssed later in section 20 or pass by reference. If you add & after a variable name in the declaration the actually variable, not a copy, is passed to the function, therefore changes to that variable within the function effect the original variable.
19.1.1
Example of passing by reference
#i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t add ( i n t a , i n t b ) ; i n t add2 ( i n t &a , i n t &b ) ;
19.2. Functions without arguments or return value – void
137
i n t main ( ) { i n t a =1; i n t b=2; cou t << a <<” ”<
19.2
Functions without arguments or return value – void
The keyword void can be used like a type, but is not really a type. It is useful to mark functions that do not have a return value. Examples are functions that just write something to the screen or to a file and functions that modify the input-variables directly. v o i d e r r o r ( s t r i n g message ){ cou t << ” e r r o r o c c u r e d : ” << message << ”\n” ; } Also functions without arguments sometimes can be useful. In C++ this is implied by an empty list of arguments like for the pseudo-randomnumber generator as declared in the C library stdlib.h: v o i d s r an d ( u n s i g n e d i n t s e e d ) ; i n t rand ( v o i d ) ;
19.3. Libraries
138
It is used by first selecting a sequence of random numbers by calling (once only) the initialisation function srand(.) with a positive number. Then, for each call of rand() a new, integer number is returned. In order to transform the integers to real numbers, one can e.g. divide by the maximum. Exercise 19.3. Use the random number generator of C++ and later the random numbers in MATLAB to generate a vector of 10 random numbers ri=1,...,10 ∈ [0, 1].
19.3
Libraries
As seen in previous examples, declarations/prototypes are sufficient for the compiler to translate a program. Wherever called in the program, the function call is prepared during compilation. The function itself can be then defined and “linked” to the program later. Function-definitions are found in so-called object-files (*.o) or libraries (see section §24 for more information of code organisation into small objects, which are compiled and linked independently). The classical example for a library is the cmath file that was included at the beginning and involves functions like the sqrt(). The declarations are found in cmath itself, and the translated/compiled definitions are found in libm.a. A program-block that uses the sqrt() function can look like this. #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( ) { d ou b le d ; cou t << ” Enter a number : ” << e n d l ; c i n >> d ; i f ( d<0 ) cou t << ”Cannot compute th e r o o t o f n e g a t i v e numbers ” << e n d l ; e l s e // compute s q r t ( d ) and p r i n t v a l u e cou t << ” s q r t ( ” << d << ” ) = ” << s q r t ( d ) << e n d l ; return 0; } The compiler must contain the linker-option “-lm” and must know the correct path where it can find the library (note, some compilers do this automatically). As a remark, under LINUX, the compilation would look like this: g++ myprog.cc -o myprog -lm In DevC++ the corresponding command can be found under “Compilation”.
19.4. inline functions
139
The short -l means “library” and m is the abbreviation for the file libm.a, that one gets by adding lib, m and the ending .a.
19.4
inline functions
In general, several things happen when a function is either called or closed. Some of this can be avoided or optimised by use of so-called inline-functions. However, we will not go into detail here. (Further reading if needed).
19.5
Overloading of functions
In contrast to C and some other languages, in C++ not only the name and type of a function, but also the types of the arguments are relevant. Therefore it is possible to define a function for each type int, double or struct Date {...}, all with the same name. The name does not have to contain type information thus. In C++, the compiler selects the right function with the appropriate type by itself. One can think of an internal function-name used by the compiler that also contains the argument-types. v o i d swap ( i n t &a , i n t &b ) { i n t tmp = a ; a = b ; b = tmp ; }
// i n t e r n a l name e . g . s w a p i n t i n t
v o i d swap ( d ou b le &a , d ou b le &b ) { d ou b le tmp = a ; a = b ; b = tmp ; }
// s w a p d o u b l e d o u b l e
void f ( ) { d ou b le a , b ; int i, j; // . . . swap ( a , b ) ; // d ou b le v e r s i o n swap ( i , j ) ; // i n t version }
19.6
Templated functions
In C++ it is possible to right functions were the type of the variables is free.
19.6. Templated functions
140
tem p late T add (T a , T b ) { r e t u r n a+b ; } The following call to the functions add(3,4) would automatically create the following code. i n t add ( i n t a , i n t b ) { r e t u r n a+b ; } That is the above templated function can be used for any type T, well, for which the operator + is defined. Multiply template arguments can be used, for example: tem p late T2 add (T1 a , T2 b ) { r e t u r n a+b ; } The call add(a,b) would add the double b to int a and return a double. That is add(2.3,4.3) would return 6.3; whereas add<double,int>(2.3,4.3) would return 6.
Exercises Exercise 19.4. Write a program that reads in ten numbers, using the swap function above sort the numbers into ascending order and write out the order list. See http://en.wikipedia.org/wiki/Bubble_sort for more information. Exercise 19.5. Write a function, which calls itself, to calculate the N th Fibonacci number. Recall f ib(N ) = f ib(N − 1) + f ib(N − 2) and f ib(1) = 0, f ib(2) = 1.
Chapter 20 Pointers, pointer-field duality, and references
20.1
Pointers
From the viewpoint of the computer, every memory-cell in the (virtual) memory is uniquely marked by a certain number (address). C++ allows to use these adresses in memory-space for programming purposes. Since it is allowed to self-define names for these address-pointers, the program can also become much more clear and readable. The declarations: int i =5; d ou b le a = 1 2 . 3 4 ; ch ar ∗ c1=” h e l l o ” ; int j =0;
// d e c l a r a t i o n o f an a r r a y o f ch ar
create the memory-entries in Fig. 20.1 (left column). Only the memory-entries (the values of the variables) occupy space in the computer memory. The names of variables do not occupy space even if one would use instead of i the more meaningful name counter. In general, there is no guarantee that sequentially defined varibales also occupy memory sequentially (except for fields). The variable c1 of type char contains a pointer to another range of memory where the values of the field are stored. The definition of *c1 reserves some range in memory that is large enough to store the word "hello". The elements 'h', 'e', 'l', 'l', and 'o' can also be accessed using the form c1[0], c1[1], c1[2], c1[3], and c1[4]. Note again that numbering in C++ always starts with 0. If one has to insert or delete a range of a sorted list (quickly and efficiently), then this is not possible using a linear field like the above *c1. A linear field is special in so far that all data are stored in subsequent positions in memory. As well inserting as removing entries from this
– 141 –
20.1. Pointers
142
f.)
f.)
e p.d
s res
ue
l
va
ad
m (co e m na
5 12.34 0xff10 0
0xfd10 0xfd18 0xfd20 0xfd28 ...
i a &c1 j
h e l l o \0
0xff10 0xff11 0xff12 0xff13 0xff14 0xff15
c1[0] c1[1] c1[2] c1[3] c1[4] c1[5]
e r-d
se
(u
... Figure 20.1: (Schematic) memory occupations (left), computer-internal memory adress (mid), and (user-defined) name of variables (right). field requires copying the full range “above” the modified element. (In average that is half the field-length to be moved). This is acceptable for short fields but not for long ones. A possible solution to this is a linked list which contains not only the values of the elements but also the information where the next element can be found. The actual location does not matter, i.e., only the names of the memory-cells have to be modified. For example, in order to remove an element x from a linked list, only the name entry of the previous element has to be changed such that it does not point to x anymore, but to the following element. This information is available in the x-element and thus just has to be copied. Deleting several subsequent entries requires the same effort and entering a (part of a) linked list from somewhere else is also rather efficient. However, due to this additional options, a linked list also usually requires more memory than a normal field. In order to allow a computer independent dealing with such objects like linked lists, C++ provides also the type pointer. A pointer can point to an arbitrary data-type – which actually could be a pointer itself. In order to declare a pointer, a (star) * is used. In order to get the address of a variable, the &-operator is used. The declarations in the program-fragment: // D e c l a r a t i o n p a r t int i = 5; i n t ∗ p i = &i ; i n t ∗∗ p p i = (& p i ) ;
// i n i t i a l i s a t i o n // p i i s a p o i n t e r to an i n t , // h e r e th e v a r i a b l e i // p o i n t e r to p o i n t e r to i n t
// How to u s e ∗ and & l e g a l l y i n th e program
20.1. Pointers
143
DATA
DATA
DATA
DATA
11111 00000 00000 11111 00000 11111 00000 11111 00000 11111
DATA
DATA
DATA
Figure 20.2: Use of pointers in a linked list. (Top) the list before an element is removed, (bottom) the list after, where the black element denotes the removed one that is not part of the list anymore.
∗p ∗∗ p p int ∗ pp p
i i i j i i
= = = = = =
// // // // // //
0; 1; 2; 7; &j ; &i ;
s e t i to 0 s e t i to 1 , p i r em ain s unchanged s e t i to 2 , p i r em ain s unchanged d e c l a r e another i n t e g e r j change p i to p o i n t on j , ∗ p i != i l e t p i p o i n t to i a g a i n
lead to memory occupation as indicated in Fig. 20.3.
0xfa10 ...
i
0xfa10 0xfc28 ... *
pi
0xfc28 0xfe08 ...
ppi
5
*
Figure 20.3: Memory occupation as in Fig. 20.1. In order to change the value of a variable a pointer points to, or in order to use this value in an operation, also the * operator is used.
20.1. Pointers
144
∗ p i = 27; ∗ p i = 2 ∗ (∗ p i ) + 5;
// i i s 27 now // e q u i v a l e n t to :
i = 2 ∗ i + 5;
Constant pointers are declared by using a const right of the pointer-symbol *. They must be initialised already at declaration, since they are fixed thereafter and cannot be changed anymore. c o n s t i n t ∗ c p i = &i ;
// ok , i can n ot be changed // th r ou gh u s e o f c p i // c p i can be changed
c o n s t ch ar n e w l i n e = ' \n ' ; c o n s t ch ar ∗ c o n s t p n l = &n e w l i n e ;
// c o n s t p o i n t e r to c o n s t ch ar // n ote : p n l = ' 0 ' ; −> e r r o r !
The * operator has thus two meanings: In a variable declaration, it marks a pointer, whereas in front of a variable (of type pointer) it leads to access on the memory (value) of the corresponding memory space. Analogously, also the & operator has two meanings: During variable declaration, it denotes a reference, whereas in front of a variable, it is the so-called address of operator, i.e. it provides the address of the variable. Note that it is possible to do arithmetics/mathematics with pointers. Above, p_i = p_i + 5 would let the pointer point to 5 int memory entries further. For this, the compiler needs to know how big the corresponding data-type is. Also the difference of pointers can be formed but that makes only sense inside a field. Navigation within a field can be done in the following way: int p [ 3 0 ] ; ∗ ( p i + 25)
= 15;
p i [25]
= 15;
// // // //
declare a f i e l d of int th e v a l u e o f th e 25 th e n t r y ( p a s t th e one p o i n t e d to by p i ) i s s e t to 15 equivalent . . .
The language guarantees that 0 is never the address of a real data-element. A pointer with value 0 can thus be used to indicate an error or, e.g., the end of a list.
20.1.1
Pointer to void
The type pointer to void is generic. It is guaranteed that any pointer can be transferred into a pointer to void, without loss of information. In C the void * was often used to transfer information to functions/routines that can deal with arbitrary pointers. (e.g. sort-function like quicksort, or the return value of malloc). In C++ it is recommended to use templatefunctions that guarantee type-consistency and type-safety, see section 19.6 for more details.
20.2. pointer-field duality
20.2
145
pointer-field duality
Between pointers and fields exists a very close relation, see above the use of [] for the “indirect” de-referencing of pointers. A field a[..] is internally transformed to a pointer on the first element of the field. Access to the field is then dealt with via the pointer-arithmetics mentioned above. This is also the reason why C++-fields always start with 0 (i.e. the localisation of field entries can be done with less operations). int a [ 2 0 ] ; int ∗ p = a ; i n t ∗ p = &(a [ 0 ] ) ; p [ 5 ] = 4; a [ 5 ] = 4; int b [ 2 0 ] [ 3 0 ] ;
// ok , a i s name o f th e f i e l d and can // be used as a d d r e s s to th e f i e l d // . . . e q u i v a l e n t // a c c e s s to a th r ou gh p o i n t e r a r i t h m e t i c , // a [ 5 ] i s s e t to th e v a l u e o f 4 // . . . e q u i v a l e n t
// // // // int ∗ r = b [ 0 ] ; // // i n t (∗ q ) [ 3 0 ] = b ; // // q [ 1 2 ] [ 1 5 ] = 26; // ( ∗ ( q + 1 2 ) ) [ 1 5 ] = 2 6 ; // ∗ ( ∗ ( q+12)+15) = 2 6 ; // b [ 1 2 ] [ 1 5 ] = 26; //
b i s now an a r r a y o f 20 a r r a y s o f 30 e l e m e n t s o f typ e i n t i n t ∗p = b ; e r r o r ! wrong type , s i n c e b i s o f typ e p o i n t e r to 30 i n t h e r e ok , r p o i n t s to th e f i r s t i n t i n th e f i r s t ( o f 20) a r r a y ( s ) o f 30 i n t s ok , q p o i n t s to th e f i r s t s e t o f 30 i n t ' s , q and b can now be used synonymous ok , s e t elem en t ( 1 3 , 1 6 ) to th e v a l u e 26 . . . equivalent . . . equivalent . . . equivalent
Exercise 20.1. Practice the use of pointers, using the above examples as a starting point.
20.3
Transfer of field-variables to functions
In order to transfer a field to a function, it is sufficient to just transfer the pointer, see sec. 19. For a one-dimensional field this is just the pointer to the first element, while for two-d fields it is a pointer to a field with a compatible, fixed number of elements. Only the first dimension of the field can be left out in this case, all others have to be specified at compile-time. This makes the C-type fields rather in-practical to be used when dynamic memory management is desired. void f ( i n t b [ ] [ 3 0 ] ) void g ( i n t (∗ q ) [ 3 0 ] ) int
b[20][30];
// f u n c t i o n p r o t o t y p e t h a t t r a n s f e r s b // f u n c t i o n p r o t o t y p e t h a t t r a n s f e r s
20.3. Transfer of field-variables to functions int int
146
c [10][30]; d[15][31];
f ( b ) ; g ( b ) ; f ( c ) ; g ( c ) ; // ok f (d ) ; g(d ) ; // e r r o r s , s i n c e s econ d d im en s ion not ==30
Summary: Transfer of Variables to Functions As summary and examples for the use of fields in functions, the example in exercise 7 is re-written in order to use functions that use the field: #i n c l u d e #i n c l u d e #i n c l u d e u s i n g namespace s t d ; int r e a d f i e l d ( int flen , int ∗ f i ) ; void w r i t e f i e l d ( i n t flen , i n t ∗ f i ) ; void s o r t f i e l d ( i n t flen , i n t ∗ f i ) ; i n t main ( i n t ar gc , ch ar ∗ ar gv [ ] ) { c o n s t i n t Mfmax=20; i n t f i [ Mfmax ] ; i n t ifmax =0; i n t ftmp ; ifmax = r e a d f i e l d ( ifmax , f i ) ; // g e t f i e l d from s u b r o u t i n e w r i t e f i e l d ( ifmax , f i ) ; // c o n t r o l what you got s o r t f i e l d ( ifmax , f i ) ; w r i t e f i e l d ( ifmax , f i ) ;
// s o r t th e f i e l d // c o n t r o l what you got
system ( ”PAUSE” ) ; return 0; } // f u n c t i o n r e a d s th e f i e l d from a n o t h e r f i e l d and r e t u r n s i t back int r e a d f i e l d ( int flen , int ∗ f i ) { c o n s t i n t f i e l d l e n g t h =17; i n t f i e l d [ f i e l d l e n g t h ] = {1 , 0 , −10, 12 , −2, 5 , 5 , 1 , −4, −2, −4, −8, 3 , 25 , 51 , −4, −5}; f o r ( i n t i =0; i
20.3. Transfer of field-variables to functions
147
return f l e n ; } // f u n c t i o n w r i t e s f i e l d to s c r e e n void w r i t e f i e l d ( i n t flen , i n t ∗ f i ) { f o r ( i n t i =0; i =1; j −−) { i f ( f i [ j ]< f i [ j −1]) { ftmp= f i [ j − 1 ] ; f i [ j −1]= f i [ j ] ; f i [ j ]= ftmp ; } } } }
Excerises Exercise 20.2. Consider the following code extract and explain the effect of each line, stating the value of a and b at all points. i n t a =15; i n t b=10; i n t ∗p1=&a ; i n t ∗p2=&b ; i n t ∗∗ p3=(&p1 ) ; ∗p1 =5; ∗p2 =20; ∗∗ p3 =1;
20.4. Dynamical Memory Management
148
∗p2=∗p1 ; p1=p2 ; ∗p1 =10; ∗p2=5 ∗∗ p3 =8; cou t << a << ” \ t ” << b << e n d l ;
20.4
Dynamical Memory Management
In order to request memory, C++ provides the operators new and new [] for single variables or for fields, respectively. This memory is allocated without a scope (see section 16.3.7) and must be freed manually. In order to free the memory, delete and delete [] have to be used. int ∗ int int ∗ // . . . delete delete [ ]
p i
= new i n t ; // d e c l a r e new v a r i a b l e w ith ou t s c o p e n = 40; p a i = new i n t [ n ] ; // d e c l a r e new a r r a y w ith ou t s c o p e p i; pa i ;
The request for memory requires the type after new, and a pointer to this new element is returned. For fields, new[] is used and the number of memory-elements within the brackets is requested. The request returns a pointer to the first element in the field. i n t ∗ p a i = new i n t [ n ] ; pa i [0]=5; pa i [1]=4; The operator new returns an “exception” bad_alloc, if the request for memory does not succeed and then terminates. It is possible to ’catch’ error and continue without ending the code, using the commands try and catch (this will not be covered by this course).
Note that in many compilers it is possible to allocate memory dynamically using VLA’s (e.g., int N=10; int a[N]; allocates a dynamic array, since N is not constant). However, we discourage you from using this, as it is not supported by the C++ standard (see http://www.informit.com/guides/co and can lead to segmentation faults when large dynamic arrays (> 106 bytes) are allocated.
Chapter 21 Object Oriented Programming I: Containers in the Standard Template Library
21.1
C++ standard classes
A container is a data structure (specifically a ‘holder object’) which can store multiple other C++ objects (its ‘elements’) in an (ordered) structure. Containers can be used to create structures which are commonly used in C++ (and indeed other programming languages) such as dynamic arrays, queues, stacks , lists, associative arrays and many more... Different containers may be used to provide a solution to the same problem; however, dependent on the specific problem at hand, some may be much more efficient than others. Therefore it is important to have a good knowledge of the various containers available to us, so that we can always choose the right container for the task, and hence make our programs as fast and functional as possible! In this chapter, we will learn how to use some of the most important STL containers (these being the predefined, ‘ready to use’ container classes from the standard template library). Later on, once we fully understand what classes are and how to work with them, we will learn how to create our own classes. Most of the objects found in the standard template library are templated to make them flexible and usable with numerous different data types – a matter which we have discussed in previous chapters. We have been using these for some time without exactly understanding the syntax. The first example we have met so far was numeric_limits::min(). So here clearly it is templated with a type, in this example int, and we call the static member function min(). Note, :: calls static member function, whose purpose we have not covered in the discussion above and will not in this short course. A second example we have seen is
– 149 –
21.2. Arrays
150
#i n c l u d e <s s tr eam> #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( ) { stringstream file name ; s t r i n g s t r e a m problem name ( ” my problem ” ) ; ofstream s c r i p t f i l e ; f i l e n a m e << problem name . s t r ( ) <<” . d i s p ” ; s c r i p t f i l e . open ( ( f i l e n a m e . s t r ( ) ) . c s t r ( ) ) ; // . . s c r i p t f i l e . close ( ); return 0; } In this example str() is a member function of stringstream that return a string. Then c_str() is a member function of string that returns a const char*, i.e. a constant character array. Full listing of all standard C++ libraries can be found at http://www.cplusplus.com. Note, many of the higher classes inherit from the more basic ones. For example both isstream and ifstream inherit from istream, this explains why both type of streams have similar methods defined and can be interchanged so easily. In the remainder of this section, we introduce and learn how to use some commonly-implemented and highly useful standard classes.
21.2
Arrays
One of the most basic types of container is the std::array, which allows us to store and access an ordered series of elements. It is important to note here that a std::array is entirely distinct from the arrays you have used thus far. The new C++11 version of an array is very different in terms of the syntax used for its declaration, and – importantly – possesses many highly valuable new features which cannot be used with the old-style C++ arrays. A std::array is written in the following form:
std::array name;
Here, the first and second terms inside the specialisation brackets, <>, can be used, respectively, to choose the type of variable to be stored (i.e. int, float, char...) and the size of the array, i.e. how many individual variables are stored. For instance, if we want an array that holds 10
21.2. Arrays
151
integer numbers, we would simply type: std::array The entire phrase std::array acts like a ‘normal’ type declaration, i.e. in the same way that if we want an integer called ‘i’ we type ’int i’, if we want an array of integers with size 10 called ‘a’ we type: std::array a Note that once the size of an std::array has been declared, there is no way to change it (to put it in C++ terms, an std::array cannot be ‘resized’). Each element of an array can be treated as an individual variable. For instance, in our hypothetical array of ints, each element is treated as an int, i.e. can be used to store a single integer value. An individual element can be accessed using square brackets containing its position within the array. For example if we want to store a value of 3 in the 1st element of our array, ‘a’, we would simply type: a[0] = 3; Note that the numbering in an array starts at zero! Below, we see a very simple example of an array being declared, each of its members being assigned a value, and then these values read out in turn: #i n c l u d e // n ote t h a t we need to i n c l u d e t h i s h ead er i f we want to u s e a r r a y s ! #i n c l u d e <ar r ay > i n t main ( ) { // d e c l a r i n g our ar r ay , such t h a t i t can t a k e up to 5 i n t e g e r v a l u e s s t d : : ar r ay a ; // a s s i g n i n g v a l u e s to each member o f th e a r r a y a [ 0 ] = 1; a [ 1 ] = 2; a [ 2 ] = 3; // n ote t h a t t h e s e v a l u e s do not have to be a s s i g n e d i n o r d e r a [ 4 ] = 5; a [ 3 ] = 4; // o u t p u t t i n g our v a l u e s , i n o r d e r f o r ( i n t i = 0 ; i < 5 ; i ++) { cou t << ”a [ ”<< i << ” ] = ” << a [ i ] << e n d l ; } return 0; } std::arrays (like other STL containers) also possess several in-built methods, which are effectively ready-to-use functions that come ‘packaged’ with a given container. The methods belonging to a container class can be accessed using the dot operator in the manner:
21.2. Arrays
152 std :: array number; number[n] number.size()
Define a list. The nth element. The length of the list.
Table 21.1: A summary of the array class containerName.method An example is the ”size()” method. For our array a, we can simply type: a.size() and this method will return, as the name implies, the size of our array (i.e. the number of elements it possesses). Note that when calling the size function we do not include the square brackets. The size method can be simply implemented in a code as follows: #i n c l u d e #i n c l u d e <ar r ay > main ( ) { // d e c l a r i n g an a r b i t r a r y p a i r o f a r r a y s s t d : : ar r ay a ; s t d : : ar r ay b ; // o u t p u t t i n g th e s i z e o f our a r r a y s u s i n g s i z e ( ) s t d : : cou t << ” Array a has ” << a . s i z e ( ) << ” e l e m e n t s ” << s t d : : e n d l ; s t d : : cou t << ” Array b has ” << b . s i z e ( ) << ” e l e m e n t s ” << s t d : : e n d l ; return 0; } Note that you can also intitialize an array while declaring it; for instance, by typing: std::array c = {true}; you can, in one line, declare all 100 elements of an array of bools as ‘true’. This is very useful if, for instance, you want to easily ‘clear’ an array. Note here the importance of the curly brackets – the code will not compile without these! Exercise 21.1. Write an array to store the squares of all the numbers between 1 and 20 and another to store the corresponding cubes. Output the data in columns alongside their root. Harder: Write a program to find all the prime numbers between 1 and 100 as efficiently as possible (Note: this question was once used as part of the interview process to become a programmer for Google – so don’t be ashamed if you need a few hints!)
21.3. Vectors
21.3
153
Vectors
std::vectors are arguably the most used, and most useful, of all container classes. std::vectors can be used exactly like std::arrays but – unlike std::arrays, they have a variable size, making them much more flexible. Vectors can either be resized ‘manually’ using the ‘resize()’ member function of the vector class. They will also automatically resize when elements are added or removed from the vector array. The resize() function, like the size() function from the previous section, is called with dot operator, i.e. vectorName.resize(newSize); where ‘newSize’ is simply the total number of elements you want your resized vector to possess. The dot operator is always used to call functions that are members of the class on which they are used. Given below is an example of the resize() function in action (as well as a reminder of the size() function):
#i n c l u d e // as with a r r a y s , we need to i n c l u d e th e r e l e v a n t h ead er which a l l o w s us to u #i n c l u d e
i n t main ( ) { i n t mySize ; // d e c l a r i n g a v e c t o r with z e r o l e n g t h ! s t d : : v e c t o r <double> v ; // o u t p u t t i n g th e s i z e o f th e v e c t o r s t d : : cou t << v . s i z e ( ) << s t d : : e n d l ; // i n c r e a s i n g th e s i z e o f th e v e c t o r . . . v . resize (10); // . . . and o u t p u t t i n g i t s new s i z e ! s t d : : cou t << v . s i z e ( ) << s t d : : e n d l ; // prompting th e u s e r to g i v e a new s i z e f o r th e v e c t o r . . . s t d : : cou t << ”How b i g do you want your v e c t o r ? ” << s t d : : e n d l ; s t d : : c i n >> mySize ; // . . . and ch an gin g th e v e c t o r s i z e a g a i n ! //As you p r ob ab ly e x p e c t by now , th e r e s i z e f u n c t i o n can t a k e u s er −d e f i n e d v . r e s i z e ( mySize ) ; s t d : : cou t << ”Your v e c t o r now has ” << v . s i z e ( ) << ” e l e m e n t s . ” << s t d : : e n d l return 0; } Vectors in fact possess a number of useful member functions, such as the push back() and pop back() functions that can be used, respectively, to add and remove elements of a given array. Although we will not discuss these functions here, you should now know enough to learn about (and use!) them on your own! Exercise 21.2. Define a zero-size vector. Based on user input, resize this vector to accommodate a given number of values. Read in values from the console to fill your vector, and then calculate the average of
21.4. Strings
154
the numbers given. Try writing a similar program using arrays – a nice example of how much more efficient vectors can be!
21.4
Strings
Another C++ function that has been ‘updated’ in the C++11 standard is the string, or now std::string. As with arrays, the new-version strings possess a wealth of functionality not available with the original version of the data type. Our first example shows a simple application of an std::string, demonstrating that their basic use is extremely similar to that of an ‘old-fashioned’ non-STL string. We use for our example a very useful real-world application of strings – the verification of a username/password pair:
// once again , we need to i n c l u d e th e n e c e s s a r y h ead er i n o r d e r to u s e our new #i n c l u d e <s t r i n g > #i n c l u d e
i n t main ( ) { // d e c l a r i n g a p a i r o f s t d : : s t r i n g s . s t d : : s t r i n g username ; s t d : : s t r i n g password ; // d e c l a r i n g and d e f i n i n g a s t r i n g i n one s t e p // n ote t h a t s t r i n g s w i l l a c c e p t p u n ctu ation , s p a c e s and i n d e e d any o t h e r c h s t d : : s t r i n g savedUsername ( ”b . g a t e s ” ) ; // n ote t h a t s t r i n g s can be d e c l a r e d and d e f i n e d i n th e above manner , but a l s t d : : s t r i n g savedPassword = ” I h 8 a p p l e ” ; // n ote i n both o f th e above t h a t th e s t r i n g to be s t o r e d must be s u r r ou n d ed s t d : : cou t << ” Enter your username : ” << s t d : : e n d l ; // n ote a l s o t h a t when r e a d i n g i n from th e c o n s o l e , you do NOT need to i n c l u s t d : : c i n >> username ; s t d : : cou t << ” Enter your password : ” << s t d : : e n d l ; s t d : : c i n >> password ; // c h e c k i n g i f username and password match i f ( ( password == savedPassword ) && ( username == savedUsername ) ) { s t d : : cou t << ” Password a c c e p t e d ” << s t d : : e n d l ; } else { s t d : : cou t << ” I n c o r r e c t username / password com b in ation . Armed gu ar d s a r e } return 0; } Next, we introduce some of the more outlandish things we can do with a std::string, for instance performing arithmetic to make phrases out of words or longer phrases out of phrases!
21.4. Strings
155
#i n c l u d e <s t r i n g > #i n c l u d e i n t main ( ) { // d e f i n i n g a s e r i e s o f words t h a t can be combined to make a s e n t e n c e s t d : : s t r i n g a = ” This ” ; // ( remember you can i n c l u d e s p a c e s i n a s t r i n g ! ) std : : s t r i n g b = ” i s ” ; s t d : : s t r i n g c = ”a ” ; std : : s t r i n g d = ” sentence . ” ; // u s i n g s i m p l e a d d i t i o n to combine a l l th e above s t r i n g s i n t o one std : : s t r i n g e = a + b + c + d ; s t d : : cou t << e << s t d : : e n d l ; return 0; } 6. Example - brute force password guesser! A nice reminder of why it is important to choose a long password and include numbers (i.e. try with different lengths, and with one including numbers. See how many steps each one takes on average and compare!) ”This sentence is just nonsense until you use some arithmetic.” As with arrays and vectors, the string container class posseses a size() method which returns the length of the string (i.e. how many individual characters it posseses). Again, just like the previous examples, the ’[]’ operator can be used to access single characters belonging to the string. For instance, simply typing: stringName[5]; will access the 6th element of our string inventively named ‘stringName’ (remember our numbering starts at zero!). A more complete example may be seen below: #i n c l u d e <s t r i n g > #i n c l u d e i n t main ( ) { // d e f i n i n g a s t r i n g , s : s t d : : s t r i n g s ( ”Can you code t h i s ? ” ) ; s t d : : cou t << s << s t d : : e n d l ; // o u t p u t t i n g i n d i v i d u a l c h a r a c t e r s from our s t r i n g , s : s t d : : cou t << s [ 4 ] << s [ 1 1 ] << s [ 1 6 ] << s t d : : e n d l ; return 0; } In fact, there are many ways you can play with strings, for instance inserting one string into another using the insert() function: // d e f i n i n g a s t r i n g s t d : : s t r i n g s ( ”C++ i s hard . ” ) ;
21.5. Maps
156
s t d : : cou t << s << s t d : : e n d l ; // i n s e r t i n g th e t e x t ” not ” at th e s t r i n g ' s 6 th elem en t . // n ote how , j u s t l i k e v e c t o r s , s t r i n g s can r e s i z e when new e l e m e n t s a r e added s . i n s e r t ( 5 , ” not ” ) ; s t d : : cou t << s << s t d : : e n d l ; Or swapping two strings using the swap() function: #i n c l u d e <s t r i n g > #i n c l u d e i n t main ( ) { // d e f i n i n g a s e t o f s t r i n g s . . . s t d : : s t r i n g a = ”Romeo” ; std : : s t r i n g b = ” l ov es ” ; std : : s t r i n g c = ” J u l i e t ” ; // . . . and o u t p u t t i n g ( n ote we a r e a g a i n u s i n g our s t r i n g a r i t h e m e t i c ! ) s t d : : cou t << a + b + c << s t d : : e n d l ; // swapping our s t r i n g s a and b u s i n g th e swap ( ) method a . swap ( c ) ; // and o u t p u t t i n g a g a i n i n th e same o r d e r . . . s t d : : cou t << a + b + c << s t d : : e n d l ; return 0; } You can also convert a number to a string using the std::to string function: s t d : : s t r i n g number = s t d : : t o s t r i n g ( 1 + 1 ) ; Exercise 21.3. Write a program which uses the ‘brute force’ method to guess a user-input password comprising three letters. Include a function that records the number of ‘attempts’ your code makes in order to break the password. Extend your code to work with 6 letter passwords. Note the difference in the average number of tries it takes for your code to break the password – this is (one reason) why longer passwords are safer!
21.5
Maps
Although the STL library contains a number of different containers, the last container class we will discuss here is the map class template. maps can be thought of as similar to arrays, in that they can store various mapped values in individual elements. Each mapped value is associated to a given key value which identifies a single element. The key is used to retrieve the value must be unique, but (unlike for arrays) can be of any type.
21.5. Maps
157
While a text-based description of maps make them sound rather complicated, their function and use becomes much clearer with an example! For instance, it is possible to define a char to act as a key for an int, allowing us to write things like: s t d : : map example ; example [ ' a ' ] = 1 0 ; ...which assigns the (integer) value 10 to the element “a”, where the character a is the key and 10 the mapped value. In the declaration, the first term within the specialisation brackets, <>, gives the type of the key to be used and the second term the type of the stored value itself. Note the similarity to the definition of a simple array! In addition to chars, strings, floats and other data types my be used to provide a key! Below is a more complete – and thoroughly explained – example of how maps can be used: #i n c l u d e #i n c l u d e <s t r i n g > // as u s u al , we need to i n c l u d e th e r e l e v a n t h ead er #i n c l u d e <map>
i n t main ( ) { // d e c l a r i n g th e map ; th e t y p e s g i v e n w i t h i n th e s p e c i a l i s a t i o n b r a c k e t s mea // th e name o f th e map i s then g i v e n s t d : : map<s t r i n g , i n t > example ; // d e f i n i n g keys and mapped v a l u e s f o r two e l e m e n t s o f our map . Note how i t example [ ”keyOne ” ] = 1 ; example [ ”keyTwo” ] = 2 ; // o u t p u t t i n g th e v a l u e s o f our two e l e m e n t s . Note t h a t th e d ou b le q u o t a t i o n s t d : : cou t << example [ ”keyOne ” ] << ' \ t ' << example [ ”keyTwo” ] << s t d : : e n d l ; // d e c l a r i n g a n o t h e r map ; n ote t h a t both th e key and mapped v a l u e s can p o s s e s t d : : map<s t r i n g , s t r i n g > anotherExample ; // . . . and d e f i n i n g a s i n g l e elem en t anotherExample [ ” t h e k e y ” ] = ” to g e t th e mapped v a l u e ” ; std : : s t r i n g a ; s t d : : cou t << ”Type i n th e key ” << s t d : : e n d l ; s t d : : c i n >> a ; // n ote t h a t th e key can be r ead i n from a c o n s o l e or an e x t e r n a l f i l e − eve // be c a r e f u l when u s i n g s p a c e s and o t h e r b r eaks , though . . . s t d : : cou t << anotherExample [ a ] ; return 0; }
21.6. Iterators
21.6
158
Iterators
So far, we have been introduced to several different C++ container classes. In this section, we will introduce the concept of iterators which provide a handy – and uniformly applicable – way in which to access the individual elements stored in a given container. An iterator can be thought of as a pointer which can be ‘pointed at’ any given element belonging to a given container. However, unlike a normal pointer, iterators also possess a series of overloaded operators and functions. This allows them to be applied to different types of container using the same, uniform syntax! In this section, we will introduce the most important of these operators and functions, before showing them in action.
21.6.1
Iterator operators
• Dereferencing operator, * : Returns the element currently being ‘pointed to’. • Increment operator, ++ : Tells the iterator to ‘point at’ the next element in the array. • Decrement operator, -- : Tells the iterator to ‘point at’ the previous element in the array. Note: this operator is not usable for all container types. • Equality operator, == : Can be used to check if two iterators are pointing to the same element of a container. Note that it does not compare the values stored in these elements – this can instead be achieved by first dereferencing the iterator! • Inequality operator, != : Can be used to check if two iterators are not pointing to the same element of a container. As above, the comparison applies to the pointer and not the values being pointed to. • Assignment operator, = : Assigns the iterator to a new position within the container. Note once again that this does not re-assign or otherwise change the value stored in the element being pointed to. In order to change the stored value, the iterator must, as above, first be dereferenced.
21.6.2
Iterator member functions
• begin() : Returns an iterator pointing to the first element in a given container – i.e. returns the beginning of the container contents! • end() : Returns an iterator corresponding to the element after the end of the elements within the container. The reason that ‘end()’ does not simply return the last element in the array but the one after it will become clear when we show some examples of how iterators are typically used. • cbegin() : Returns a constant, i.e. ‘read-only’ iterator pointing to the first element in a given container.
21.6. Iterators
159
• cend() : Returns a constant iterator corresponding to the element after the end of the elements within the container.
21.6.3
Declaring and using iterators
The generic declaration of an iterator follows the below form: c o n a t i n e r t y p e : : i t e r a t o r name ; So, as an example, if we want to create an iterator which works with std::vectors of integers, and we want to name it ‘it’, we would simply type: s t d : : v e c t o r : : i t e r a t o r i t ; In addition to ‘normal’ iterators, we can also create a constant or ‘read-only’ iterator, const iterator. The declaration of these read-only iterators is the same as for a normal iterator, for example: s t d : : v e c t o r : : c o n s t i t e r a t o r i t ; would provide a read-only iterator which we can apply to any std::vector-type containers holding integer elements. Now that we know how to declare an iterator, the next stop is to see one at work. The code below shows a (very!) simple example of an iterator being used to cycle through the elements of a vector: #i n c l u d e #i n c l u d e i n t main ( ) { // D e c l a r i n g an s t d : : v e c t o r , v , and s t o r i n g // th e i n t e g e r v a l u e s 0−5 s t d : : v e c t o r v = { 0 , 1 , 2 , 3 , 4 , 5 } ; // d e c l a r i n g an i t e r a t o r , ' i t ' , s u i t a b l e f o r u s e // with th e above−d e f i n e d s t d : : v e c t o r s t d : : v e c t o r : : i t e r a t o r i t ; i t = v . begin ( ) ; // c r e a t i n g a w h i l e l o o p which r u n s u n t i l we r e a c h // th e end o f th e v e c t o r w h i l e ( i t != v . end ( ) ) { // O u tp u ttin g th e v a l u e a s s i g n e d to th e c u r r e n t // elem en t b e i n g p o i n t e d to u s i n g th e // d e r e f e r e n c e o p e r a t o r , ∗ . s t d : : cou t << ∗ i t << ” ” << ' \ t ' ; // i n c r e m e n t i n g ' i t ' to move on to th e n ext // elem en t o f th e v e c t o r
21.6. Iterators
160
++i t ; }
}
From this example it is easy to see why the ‘end()’ member function corresponds to one after the end of the current container as described in section 21.6.2 – otherwise, a loop such as that shown above would always ‘cut off’ the last element! While the above code shows us how to use an iterator, this particular example does not do a great job of showing why we should use them – i.e. what advantages they carry over other methods. In short, there are two main advantages to iterators – efficiency and generality. For example, passing an iterator to a function is much more efficient than passing an entire vector! One of the real beauty of iterators, however, is their generality – i.e. the same basic code structure will work for any container, irrespective of the functions it does or doesn’t possess, the way in which it is populated or the manner in which it stores data. For example, let’s say we want to write a code that sums all the elements of a given container. Writing such a code that works for one type of container – say std::vectors – should, by now, be quite simple for us: d ou b le vectorSum ( s t d : : v e c t o r <double> v ) { // d e c l a r i n g a v a r i a b l e to s t o r e our sum and // i n i t i a l i s i n g i t with a v a l u e 0 d ou b le sum = 0 ; // l o o p i n g o v e r a l l e l e m e n t s o f th e v e c t o r a r r a y . . . f o r ( i n t i = 0 ; i < v . s i z e ( ) ; i ++) { // . . . and , f o r each element , ad d in g i t s v a l u e // to th e sum sum += v [ i ] ; } // r e t u r n i n g th e sum o f th e v e c t o r to th e u s e r . r e t u r n sum ; } While this implementation will work just fine for an std::vector, what if we wanted to do the same for an std::array or an std::list, or indeed any other kind of container? By taking advantage of the use of iterators, we can create a sum function that will work for almost any container. One way of implementing such a function would be as follows: // c r e a t e s a t e m p l a t e typ e c a l l e d ” C o n t a i n e r ” //when th e code i s run , be used to r e p r e s e n t // e . g . s t d : : v e c t o r s , s t d : : a r r a y s . . . t e m p l a t e // A l l we t e l l th e code at t h i s p o i n t i s t h a t // t a k e a s i n g l e argument , w ith ou t s p e c i f y i n g // v a r i a b l e to be p a s s e d !
which can , any c o n t a i n e r ,
our f u n c t i o n w i l l th e typ e o f th e
21.6. Iterators
161
d ou b le generalSum ( C o n t a i n e r & c o n t a i n e r ) { //As b e f o r e , d e c l a r i n g a v a r i a b l e to s t o r e our sum and // i n i t i a l i s i n g i t with a v a l u e 0 d ou b le sum ; // d e f i n i n g an i t e r a t o r to p o i n t at th e f i r s t elem en t o f our // i n s t a n c e , ” c o n t a i n e r ” o f our unknown c l a s s , ” C o n t a i n e r ” . typename C o n t a i n e r : : i t e r a t o r i t = c o n t a i n e r . b e g i n ( ) ; // Using our i t e r a t o r to l o o p th r ou gh a l l e l e m e n t s o f our // unknown c o n t a i n e r w h i l e ( i t != c o n t a i n e r . end ( ) ) { // summing each i n d i v i d u a l elem en t . // Note th e u s e o f th e d e r e f e r e n c e o p e r a t o r , ∗ , to e n s u r e //we a r e summing v a l u e s o f th e ∗∗ s t o r e d e l e m e n t s t h e m s e l v e s ∗∗ sum += ∗ i t ; //No d e r e f e r e n c e o p e r a t o r , ∗ , i . e . h e r e i t i s th e // ∗∗ p o s i t i o n ∗∗ o f th e i t e r a t o r b e i n g in cr em en ted , // ∗∗NOT∗∗ th e v a l u e o f i t s c o n t e n t s ! i t ++; } // r e t u r n i n g th e sum o f th e unknown c o n t a i n e r to th e u s e r . r e t u r n sum ; } The second implementation of our function requires only an extra three lines of code, yet can be used for a wide variety of dissimilar containers – clearly, this is much simpler (and neater!) than recreating the same code for all different container types. Exercise 21.4. Without running the below code, comment each line and predict what the relevant outputs will be at each stage. Then, run the code to see if you were right! #i n c l u d e #i n c l u d e i n t main ( ) { s t d : : v e c t o r v = { 0 , 1 , 2 , 3 , 4 , 5 } ; s t d : : v e c t o r : : i t e r a t o r i t ; i t = v . begin ( ) ; w h i l e ( i t != v . end ( ) ) { s t d : : cou t << ∗ i t << ” ” << ' \ t ' ; ++i t ; } s t d : : cou t << s t d : : e n d l ; i t = v . begin ( ) ; w h i l e ( i t != v . end ( ) ) { i t ++; s t d : : cou t << ∗ i t << ” ” << ' \ t ' ; ++i t ; }
21.7. Range-Based for loops
162
s t d : : cou t << s t d : : e n d l ; i t = v . begin ( ) ; w h i l e ( i t != v . end ( ) ) { ( ∗ i t )++; s t d : : cou t << ∗ i t << ” ” << ' \ t ' ; ++i t ; } s t d : : cou t << s t d : : e n d l ; } Using iterators, add to the above a section of code which outputs the elements of the same vector array in reverse order. Re-write both the vector and general sum functions defined in section 21.6.3 to give the product of all the numbers in a given container. Call both functions for i) an std::vector of your choosing and ii) a similar std::array.
21.7
Range-Based for loops
In this section, we introduce range-based for loops, which provide a convenient alternative to ‘normal’ for loops, and a more elegant syntax than iterators when working with container-type objects. Say we have a simple std::vector, v, which stores some integer elements: s t d : : v e c t o r v = { 0 , 1 , 2 , 3 , 4 , 5 } ; If we wanted to output all the elements of v to the console, we would normally write something along the lines of: f o r ( i n t i = 0 ; i < v . s i z e ( ) ; i ++) { s t d : : cou t << v [ i ] << s t d : : e n d l ; } However, this notation requires you to call the v[i] operator repeatedly, which is costly, and thus should be avoided. For improved efficiency, we can instead use iterators, as we have seen in the previous chapter: f o r ( v e c t o r : : i t e r a t o r i t=v . b e g i n ( ) ; i t !=v . end ( ) ; i t ++) { s t d : : cou t << ∗ i t << s t d : : e n d l ;
21.7. Range-Based for loops
163
} However, this is – to put it bluntly – rather ugly, which is why C++11 introduced the abovementioned range-based for loops. In C++11, we can perform the same operation using a different syntax, which may in fact be more familiar to those with expertise in other programming languages: for ( int i : v) { s t d : : cou t << i << s t d : : e n d l ; } This is equivalent to the following: v e c t o r : : i t e r a t o r b e g i n = v . b e g i n ( ) ; v e c t o r : : i t e r a t o r end = end ( ) ; f o r ( ; i t != end ; i t ++) { v e c t o r i =∗ i t ; s t d : : cou t << i << s t d : : e n d l ; } As we can see, the new syntax is much more concise than the usual, non-range-based form. However, for those already familiar with using ‘normal’ C++ for loops, there are certain pitfalls that we must avoid, and certain new tricks we must learn. In the argument of the for loop, (int i) in essence tells the compiler to assign to the variable ‘i ’ the values corresponding to each of the elements of v in turn – i.e. in the above example, i ‘becomes’ each of the values stored in v, is output, and then ‘becomes’ the next one and so on. This is why in the methods section of the loop – ‘{}’ – instead of writing std::cout << v[i] << std::endl;, we write std::cout << i << std::endl;. In fact, if we accidentally output v[i] instead of i, we can end up with some very confusing results (as demonstrated in the exercises at the end of this section!). It is additionally important to note that if we want to use range-based for loops not just to ‘look at’ data but to actually alter the values stored, we need to make our loop variable (i) a reference. This is done simply by adding the usual ‘&’ symbol to our integer declaration. So if, for example, we want to increment each of the values stored in our vector, we would write: f o r ( i n t& i : v ) { i ++; } Of course, range-based for loops don’t only work with vectors – we can also use them with many other container types. For instance std::strings:
21.7. Range-Based for loops
164
s t d : : s t r i n g s = ” example ” ; f o r ( ch ar i : s ) { s t d : : cou t << ” [ ” << i << ” ] ” ; } where the above example would output: [e][x][a][m][p][l][e] There are many, many other ways to use range-based for loops for all kinds of different containers, and the best way to learn more about these possibilities is to spend some time playing around with them! Exercise 21.5.
Without running the below code, try and predict its output at each point, and explain why you would expect this output. Comment the code accordingly. Then, run the code to see if you were correct! #i n c l u d e #i n c l u d e i n t main ( ) { s t d : : v e c t o r v = { 0 , 1 , 2 , 3 , 4 , 5 } ; for ( int i : v) { s t d : : cou t << i << ' \ t ' ; } s t d : : cou t << s t d : : e n d l ; for ( int i : v) { i ++; s t d : : cou t << i << ' \ t ' ; } s t d : : cou t << s t d : : e n d l ; for ( int i : v) { i ++; } for ( int i : v) { s t d : : cou t << i << ' \ t ' ; } s t d : : cou t << s t d : : e n d l ; for ( int i : v) { s t d : : cou t << i << ' \ t ' ; } s t d : : cou t << s t d : : e n d l ;
21.7. Range-Based for loops
for ( int i : v) { s t d : : cou t << v [ i ] << ' \ t ' ; } s t d : : cou t << s t d : : e n d l ; return 0; }
165
Chapter 22 Object Oriented Programming II: Creating New Classes
Object-oriented programming (OOP) is a programming style where objects - data structures that consist of both data fields and methods - are used to design computer programs. In C++ this is done using classes.
22.1
A simple OOP problem
A class can be used to declare structures which require both data storage and functions acting on that data. In the following example, a rectangular shape is defined. The shape of a rectangle is defined by its width and height; this is the data contained in the class. Further, there are many properties of a rectangle that can be evaluated from the data, for example the area or circumference of the rectangle; these class-specific functions can be implemented as part of the class. #i n c l u d e u s i n g namespace s t d ; c l a s s Rectangle { d ou b le width , h e i g h t ; public : R e c t a n g l e ( d ou b le w, d ou b le h ) { s e t V a l u e s (w, h ) ; } v o i d s e t V a l u e s ( double , d ou b le ) ; i n t getAr ea ( ) { r e t u r n ( width ∗ h e i g h t ) ; } }; v o i d R e c t a n g l e : : s e t V a l u e s ( d ou b le w, d ou b le h ) { i f (w>0 && h>0) { width = w ;
– 166 –
22.1. A simple OOP problem
}
167
height = h ; } else { c e r r << ” E r r o r i n R e c t a n g l e : : s e t V a l u e s : ” << ” h e i g h t and width need to be p o s i t i v e ” << e n d l ; e x i t ( − 1); }
i n t main ( ) { R e c t a n g l e r ectA ( 3 , 4 ) , r ectB ( 5 , 6 ) ; cou t << ” r ectA a r e a : ” << r ectA . getAr ea ( ) << e n d l ; cou t << ” r ectB a r e a : ” << r ectB . getAr ea ( ) << e n d l ; return 0; }
• The Class-Definitions appear before the main() program, which is especially short. Class definitions can be placed in separate files and this is normal the case for large projects. This is discussed further in section 24. • A class is declared outside by the keyword class followed by the class name, the body in {}-parentheses, and a semicolon. It can be declared locally (i.e. inside a function), but is usually declared globally. The body contains the declaration of the member variables and member functions. • A class like Rectangle is a data structure that can contain both member variables and member functions. In this case, the member variables are the height and width of the rectangle. The member functions are used to manipulate, read and write the member variables. In this case, setValues is used to set the dimensions of the rectangle (it also checks if the values make sense), getArea is used to evaluate its area. • Members (variables and functions) are declared inside the class body. However, they can be defined both inside and outside the body of the class. If defined outside, the scope operator (class_name::member_name) is used to identify the function (see setValues). • Encapsulation by access specifiers: By default members of a class are private, i.e., they cannot be called from outside the class (try using the variable rectA.width in the function main). You can make members public, i.e. accessible from outside the class by adding the line public:; all following members will then be accessible. Public members of a class are called using the dot operator (object_name.member_name). • A constructor and a destructor can be defined for each class, which specifies what to do when an object of the class is created or destroyed. This is often used to set default values; the constructor is declared similar to a member function, with the same name as the class, but with no output type. A preceding tilde is used for the destructor. One can create constructors that take input variables, as in this example. Then an object of a class can be initialized with the () operator: Rectangle rectA(3,4);
22.2. Inheritance
22.2
168
Inheritance
Classes can also be inherited, which means that one can create a ‘child’ of a class which has all the properties of the ‘parent’ class, plus a few extra properties. For example, we can add colour to the definition of our rectangle: #i n c l u d e #i n c l u d e <s t r i n g > u s i n g namespace s t d ; c l a s s R e c t a n g l e { /∗ . . . ∗/ } ; c l a s s ColouredRectangle : p u b lic Rectangle { s t r i n g Colour ; public : C o l o u r e d R e c t a n g l e ( d ou b le w, d ou b le h ) : R e c t a n g l e (w, h ) { Colour = ” w h ite ” ; } v o i d s e t C o l o u r ( s t r i n g c ) { Colour=c ; } ; s t r i n g g e t C o l o u r ( ) { r e t u r n Colour ; } ; }; i n t main ( ) { C o l o u r e d R e c t a n g l e r ectA ( 3 , 4 ) , r ectB ( 5 , 6 ) ; r ectB . s e t C o l o u r ( ” b l a c k ” ) ; cou t << ” r ectB c o l o u r : ” << r ectB . g e t C o l o u r ( ) << e n d l ; return 0; }
• To inherit from an existing class, we use a colon : in the declaration of the derived class: c l a s s d e r i v e d c l a s s n a m e : p u b l i c b a s e c l a s s n a m e { /∗ . . . ∗/ } ; The class has now all the member variables and functions of the parent class. Additional members are specified in the class body. • We also use the colon if we want to inherit from the constructors or destructors of the parent class. In this example, the constructor of ColouredRectangle calls the constructor of Rectangle before initialising the Colour string.
22.3
Polymorphism
Inheritance is a relatively easy concept to understand. Polymorphism on the other hand is much harder. Polymorphism is about an object’s ability to provide context when methods or operators are called on the object.
22.3. Polymorphism
169
Definition of polymorphism: In object-oriented programming, polymorphism (from the Greek meaning “having multiple forms”) is the characteristic of being able to assign a different meaning to a particular symbol or “operator” in different contexts.
The simple example is two classes that inherit from a common parent and implement the same virtual method. #i n c l u d e #i n c l u d e #i n c l u d e u s i n g namespace s t d ; c l a s s Shape { public : v i r t u a l d ou b le getAr ea ( ) { } ; }; c l a s s C i r c l e : p u b l i c Shape { private : d ou b le r a d i u s ; public : C i r c l e ( d ou b le r ) : r a d i u s ( r ) { } ;
};
d ou b le getAr ea ( ) { r e t u r n M PI∗ r a d i u s ∗ r a d i u s ; }
c l a s s R e c t a n g l e : p u b l i c Shape { private : d ou b le width , h e i g h t ; public : R e c t a n g l e ( d ou b le w, d ou b le h ) : width (w) , h e i g h t ( h ) { } ;
};
d ou b le getAr ea ( ) { r e t u r n width ∗ h e i g h t ; }
i n t main ( ) { Circle c (10); Rectangle r ( 1 0 , 5 ) ; v e c t o r <Shape∗> L i s t O f S h a p e s ( 2 ) ; L i s t O f S h a p e s [ 0 ] = &r ;
22.3. Polymorphism
170
L i s t O f S h a p e s [ 1 ] = &c ; f o r ( i n t i =0; i getAr ea ( ) << e n d l ; return 0; } In this example, we create two classes, one for rectangular and one for circular shapes. We want to be able to calculate the area for both shapes. Therefore, we create a base class Shape which does nothing but declare a function getArea(). Then we create the classes Circle and Rectangle by inheriting from Shape. Thus they inherit the getArea() function. One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. This can be used to create pointers which can point to any kind of shape and which allow access to the member variables and functions inherited from the parent class. In order for a parent class pointer to use a inherited function definition, we have to declare the parent member function as virtual. Exercise 22.1. For Experts: Think about what can be improved in the following code – for this you first will have to understand ... Further reading/learning required. #i n c l u d e < s t d l i b . h> #i n c l u d e #i n c l u d e u s i n g namespace s t d ; c l a s s CSample { public : CSample ( ) ; // c o n s t r u c t o r ∼CSample ( ) ; // d e s t r u c t o r i n t I n p u t ( c o n s t ch ar ∗ fname ) ; d ou b le GetSum ( ) ; d ou b le GetMax ( ) ; int Size ; private : i n t Nmax ; d ou b le ∗a ; b o o l mem alloc ; }; i n t CSample : : I n p u t ( c o n s t ch ar ∗ fname ) { i f s t r e a m i n ( fname ) ; i n >> Nmax ; S i z e = Nmax ;
22.3. Polymorphism //memory a l l o c a t i o n a = new d ou b le [ Nmax ] ; mem alloc=t r u e ; f o r ( i n t i =0; i > a [ i ] ; in . clos e ( ) ; return 1; } d ou b le CSample : : GetSum ( ) { d ou b le sum ; sum = 0 ; f o r ( i n t i =0; i m) m = a [ i ] ; r e t u r n m; } CSample : : CSample ( ) { mem alloc = f a l s e ; a = 0; Nmax = 0 ; } CSample : : ∼CSample ( ) { // f r e e memory i f ( mem alloc ) d e l e t e [ ] a ; } //= MAIN PROGRAM ============================== // Uses th e c l a s s CSample // to r ead i n data , p r i n t th e s i z e o f th e data−f i e l d , // compute th e sum of , and th e maximum . i n t main ( ) {
171
22.4. C++ standard classes
172
CSample Test ; Test . I n p u t ( ” data . dat ” ) ; cou t << ” S i z e = ” << Test . S i z e << ”\n” ; cou t << ”Sum = ” << Test . GetSum ( ) << ” \n” ; cou t << ”Max = ” << Test . GetMax ( ) << ” \n” ; cou t << e n d l ; system ( ”PAUSE” ) ; return 0; } Exercise 22.2. Below you see a simple class definition to store name of contacts. Create an inherited class that can also store the occupation of a person. c l a s s Contact { //member v a r i a b l e s string first name ; s t r i n g last name ; public : //member f u n c t i o n s v o i d s et n am e ( s t r i n g , s t r i n g ) ; s t r i n g get name ( ) ; }; s t r i n g Contact : : get name ( ) { s t r i n g name ; name += f i r s t n a m e ; name += ” ” ; name += l a s t n a m e ; r e t u r n name ; } v o i d Contact : : s et n am e ( s t r i n g f i r s t , s t r i n g l a s t ) { first name = f i r s t ; last name = l a s t ; }
22.4
C++ standard classes
All the C++ libraries contain objects and most of these are templated. We have been using these for some time without exactly understanding the syntax. The first example we meet was numeric_limits::min(). So here clearly it is templated with a type, in this example int, and we call the static member function min(). Note, :: calls static member function, whose purpose we have not covered in the discussion above and will not in this short course.
22.5. STL vector
173
A second example we have seen is #i n c l u d e <s s tr eam> #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( ) { stringstream file name ; s t r i n g s t r e a m problem name ( ” my problem ” ) ; ofstream s c r i p t f i l e ; f i l e n a m e << problem name . s t r ( ) <<” . d i s p ” ; s c r i p t f i l e . open ( ( f i l e n a m e . s t r ( ) ) . c s t r ( ) ) ; // . . s c r i p t f i l e . close ( ); return 0; } In this example str() is a member function of stringstream that return a string. Then c_str() is a member function of string that returns a const char*, i.e. a constant character array. Full listing of all standard C++ libraries can be found at http://www.cplusplus.com. Note, many of the higher classes inherit from the more basic ones. For example both isstream and ifstream inherit from istream, this explains why both type of streams have similar methods defined and can be interchanged so easily.
22.5
STL vector
A very useful templated class in C++ is the STL vector. This is a container that can take any type of data i.e. int, double or even a user-defined class. Below we briefly introduce this very useful standard template library (STL) class. #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( ) { int n = 0; co ut << ” Enter how many s q u a r e numbers t o compute : ” << e n d l ; c i n >> n ; // Decla y an i n t e g e r a r r a y o f l e n g t h n v e c t o r my vec ( n ) ; // A s s i g n t h e v a l u e i s q u a r e d t o ea ch element f o r ( i n t i =0; i
22.5. STL vector
174
my vec [ i ]= i ∗ i ; // Write out ea ch element ' s v a l u e t o t h e s c r e e n f o r ( i n t i =0; i
A major advantage of vector is that it supports dynamic size control, i.e. by calling my_vec.resize(20) you can change the size of my_vec after creation; this is useful when the size of a field is not known at compile-time. In the above examples my_vec is a class which has both data (in this case integers) and functions (e.g. resize or sum). valarray is a very similar container class vector but can only store numerical data. This is implemented in the header . Access to data stored, in both valarray and vector classes can be slower than pointer based method described in §16.3.8, but the use of iterators (not covered by this course) can massively improve access time for these classes.
Chapter 23 I/O (Input and Output)
The I/O in C++ is completely renewed as compard to C. This was mostly necessary because of the complex format in C with non-constant number of variables. The two most important objects are I/O-channels like istream and ostream. Both are declared in the header iostream. In the previous chapters, the standard I/O channels ‘cin’ and ‘cout’ with the operators ‘<<’ or ‘>>’ were already used frequently. In the following alternatives and extensions are explained. In which sequence is I/O processed? #i n c l u d e // The programmer t y p e s t h i s cou t << ” S a l a r y : ” << Person . mSalary ; //
. . . but th e c o m p i l e r r e a d s t h i s : ( cou t << ” S a l a r y : ” ) << Person . mSalary ;
In order to write the string Salary: to the screen, the operator << is called from the ostream cout and returns another ostream with which the next << is called. This time, Person.mSalary is the second argument. Analogously after an input with cin, another istream is returned so that one can input again.
23.1
Elementary functions of iostreams
Instead of the form as used up to now, I/O can also be performed in the form of functions – for compatibility. However, the function-form has much wider range of applications, see Tab. 23.1.
– 175 –
23.2. Formatting
176
ch ar c1= ' x ' ; cou t << c1 << ' \n ' ; cou t . put ( c1 ) ; cou t . put ( ' \n ' ) ; ostream::put (char c); Example: cout.put( c1 ); char c=’x’; cout << c; istream::get (char c); Example: cin.get( c1 ); char c; cin >> c;
// Syntax used up to now // E q u i v a l e n t form u s i n g f u n c t i o n s
writes character c to ostream For comparison ... also writes the char ’c’ reads character c from istream For comparison ... Reads character c, ignores SPACE, TAB, EOL
Table 23.1: Prototypes of some element-functions for I/O alternative to the use of cout und cin. There are many related element-functions like this that allow a much more controlled and wellbehaved input and output of data. (Further reading if needed).
23.2
Formatting
Typically it is necessary to change the format of the output, e.g., in order to obtain a better readable table, or in order to prepare the output for the transfer to another software, or to write the full precision on the screen, or ... see Tab. 23.2 for a summary. Manipulator int width=12; cout << setw(width); int prec=5; cout << setprecision(prec); char c='*'; cout << setfill(c); boolapha
noboolalpha
Description sets the minimal number of digits for the following output only. Changes the number of digits behind the comma, or the max. number of digits Defines a filling-symbol as, e.g., *. Boolean values are written as textual version, i.e., true not 1 for a true value and false not 0 for a false value. Default. Has the opposite effect of boolaphla.
Table 23.2: Examples of formatting functions for the output In order to call these functions, first use: #include. Note that there are modifications that only act on the next output, and others that remain active permanently. #i n c l u d e
23.3. Files
177
d ou b le x = 1 2 3 4 . 5 ; // l e a d s to : 1 2 3 4 . 5 cou t << x << ' \n ' ; cou t << s e t f i l l ( ' ∗ ' ) << setw ( 1 0 ) << s e t p r e c i s i o n ( 5 ) ; cou t << x << ' \n ' ; // l e a d s to : ∗ ∗ ∗ ∗ 1 2 3 4 . 5 cou t << x << ' \n ' ; // back to p r e v i o u s s e t t i n g : 1 2 3 4 . 5 Furthermore there exist switches (flags) for the formatted output that need no parameters, as summarised in Tab.23.3: Flag left right internal dec hex oct showbase showpos uppercase fixed scientific
Group adjustfield adjustfield adjustfield basefield basefield basefield
floatfield floatfield
function left-adjust right-adjust +/- left decimal numbers hexadecimal numbers octal numbers shows the dec-basis of hex- and oct-numbers prints ’+’ before number if positive E, X, A-F instead of: e, x, a-f Fixed-point notation scientific notation
Table 23.3: Flags for the formatted output of data
In order to activate flags one can use alternatively cou t . s e t f ( i o s : : ' f l a g ' , i o s : : ' group ' ) cou t << s e t i o s f l a g s ( i o s : : ' f l a g ' , i o s : :
' group ' )
where the possibilities for 'flag' and 'group' are summarized above in Tab. 23.3, where the second parameter is not always needed. In order to change the setting, or set it to default, for a single flag or for groups of flags, one can use:
23.3
cou t . u n s e t f ( i o s : : ' f l a g ' ) cou t << r e s e t i o s f l a g s ( i o s : :
' flag ' )
cou t . u n s e t f ( i o s : : ' group ' ) cou t << r e s e t i o s f l a g s ( i o s : :
' group ' )
Files
For reading and writing on files, one can use the channels fstream and ofstream. These are derived from the std-streams istream and ostream.
23.3. Files
178
# i n c l u d e ... d ou b le z = 1 . 2 3 4 ; int m=5; o f s t r e a m o u t s ( ” f i l e n a m e ” , i o s : : out ) ;
o u t s << x << ' \n ' ; o u t s << j << ' \n ' ; outs . c l o s e ( ) ; ifstream ins
// open th e f i l e with name // ' f i l e n a m e ' f o r w r i t i n g // i o s : : out can be s k i p p e d // th e u s e o f th e s e l f −d e f i n e d output −stream // ' o u t s ' i s a n a l o g o u s to th e u s e o f ' cou t ' // c l o s e th e out−f s t r e a m ' o u t s '
( ” filename ” , ios : : in ) ;
i n s >> z ; i n s >> m; ins . close ( ) ;
// open th e f i l e with name // ' f i l e n a m e ' to r ead from // i o s : : i n can be s k i p p e d // th e u s e o f th e s e l f −d e f i n e d in p u t−stream // ' i n s ' i s a n a l o g o u s to th e u s e o f ' c i n ' // c l o s e th e in −f s t r e a m ' i n s '
At least now, when working with files, we need information whether we have reached the end of the file (EOF) or if the opening of the file was successful. For this, the so-called statusinformations can be used, which return – dependent on the status of a file – either true or false: // tr u e , i f no e r r o r o c c u r e d i n stream ' i n s ' // tr u e , i f th e end o f f i l e / stream i s r e a c h e d // tr u e , i f an hardware e r r o r o c c u r e d // tr u e , i f a l o g i c a l e r r o r or a // hardware e r r o r o c c u r e d i n s . c l e a r ( ) // s e t i n s . good ( ) to t r u e ins . clear ( ios : : f a i l b i t | ins . rdstate () ) // s e t f a i l ( ) manually to t r u e
i n s . good ( ) ins . eof () i n s . bad ( ) ins . f a i l ()
Example: How to read from a file to its end? The following examples show which problems can occur doing this. int n; while ( ! cin . eof ()){ c i n >> n ; // . . . . t h i s r e a d s too f a r } w h i l e ( ( c i n >> n ) . good ){ // . . . t h i s r e a d s not f a r enough } w h i l e ( c i n >> n ){
23.3. Files // . . . t h i s i s th e way i t works }
179
Chapter 24 Organisation implementation and header-files
Big programs and program-packages should not be kept in a single file since this can lead to long compilation times and non-clear dealing with and navigation in the file. Furthermore it causes big trouble if more persons work on (a single file) at the same time. Therefore, one typically splits programs into several files (projects), that can be compiled independently from each other. There are compilable (Implementation-) C++-files with the extension .cc or .cpp. Files that only contain declarations are called header-files and are used to make functions and data from one file known to another. These have the extension .h. In general (except for main.cc) an implementation-file comes together with a header-file. header-files should contain: 1. so-called include-guards, that hinder the multiple inclusion of header-files (required by the standard) #i f n d e f HEADER H #d e f i n e HEADER H // d e c l a r a t i o n s #e n d i f 2. Declarations of functions that are used amongst several modules. For declarations of local functions, another header-file can be used. 3. Definition of inline functions 4. Declaration of classes and their elementfunctionen 5. extern declarations of global variables, and declaration of static varbiables 6. Declaration and definition of template-functions and -classes
– 180 –
181 implementation-files should contain: 1. Implementation of elementfunctions of not-template-classes 2. Implementation of regular functions 3. Declaration von file-scope, class-scope and global static variables Exercise 24.1. For example, the Sample class in exercise 9.1 is long, and we want our code to be more structured. Thus, we copy the class declaration (lines 5-19 of the code in exercise 9.1) into a header file Sample.h, and copy the class member declaration (line 21-69 of the code in exercise 9.1) into a implementation file Sample.cpp, where we have to add some include directives at the beginning of the file. We tell the compiler where to find the class declaration by adding #include "Sample.h" to teh implementation files. This gives our code structure. The whole programm can now be compiled with the command g++ main.cpp Sample.cpp. Sample.h: #i f n d e f Sample H #d e f i n e Sample H c l a s s CSample { public : CSample ( ) ; // c o n s t r u c t o r ∼CSample ( ) ; // d e s t r u c t o r i n t I n p u t ( c o n s t ch ar ∗ fname ) ; d ou b le GetSum ( ) ; d ou b le GetMax ( ) ; int Size ; private : i n t Nmax ; d ou b le ∗a ; b o o l mem alloc ; }; #e n d i f Sample.cpp #i n c l u d e < s t d l i b . h> #i n c l u d e #i n c l u d e #i n c l u d e ” Sample . h” u s i n g namespace s t d ; // . . . ( copy l i n e 21−69 o f th e code i n e x e r c i s e 9 . 1 h e r e )
24.1. Compiling and linking
182
main.cpp #i n c l u d e < s t d l i b . h> #i n c l u d e #i n c l u d e #i n c l u d e ” Sample . h” u s i n g namespace s t d ; // Uses th e c l a s s CSample // to r ead i n data , p r i n t th e s i z e o f th e data−f i e l d , // compute th e sum of , and th e maximum . i n t main ( ) { CSample Test ; Test . I n p u t ( ” data . dat ” ) ; cou t << ” S i z e = ” << Test . S i z e << ”\n” ; cou t << ”Sum = ” << Test . GetSum ( ) << ” \n” ; cou t << ”Max = ” << Test . GetMax ( ) << ” \n” ; cou t << e n d l ; system ( ”PAUSE” ) ; return 0; }
24.1
Compiling and linking
Whenever we use the g++ compiler we actually do two steps: compiling and linking. Let us consider the above example. One can compile the code using the -c flag e.g. g++ -c main.cpp and g++ -c Sample.cpp. This will create object files called main.o and Sample.o. These separate objects are then linked into an executable by calling g++ main.o Sample.o -o main.exe.
Chapter 25 Functional Programming
Functional programming is very useful - being able to pass a function to another function is often highly useful while sorting items, for instance. Functional programming allows us to sort objects using more complex criteria than simply ‘bigger than’ or ‘smaller than’. This concept of using functions as variables forms the basis of functional programming. In C++ there are multiple ways to do this.
25.1
Function Pointers
Consider a (very simple) function which simply acts to return an integer variable: i n t giveMeFive ( ) { return 5; } In the above, ‘giveMeFive’ is the name of the function, and ‘giveMeFive’ can be considered as a constant pointer to the code containing the function’s methods. In other words, the pointer ‘giveMeFive’ points to the memory address where the code corresponding to the function starts. So, we can consider our call to the function ‘giveMeFive’ as an instruction to our compiler to ‘jump’ to the memory address corresponding to the function! To illustrate the equivalence between functions and pointers, try running the following example: // f o r cin , cou t e t c .
– 183 –
25.1. Function Pointers
184
#i n c l u d e // d e c l a r i n g and d e f i n i n g th e f u n c t i o n i n t giveMeFive ( ) { return 5; } i n t main ( ) { // C a l l i n g th e f u n c t i o n and o u t p u t t i n g th e r e t u r n v a l u e s t d : : cou t << giveMeFive ( ) << s t d : : e n d l ; //A common c o d i n g e r r o r ! s t d : : cou t << giveMeFive << s t d : : e n d l ; } Depending on your compiler, for the 2nd cout, your code will likely either return the integer ‘1’, or a hexadecimal value. This value printed out is the address at which your function code is stored. This is also a very good illustration of how a very simple error (missing the ‘()’ from your function) could potentially cause some very serious bugs in your code! So, if the ‘normal’ declaration above gives us a constant pointer to a function, can we also declare a non-constant pointer to a function? The answer, of course, is yes, and these function pointers can prove highly useful. Standard pointers, as we have already learned, can be declared fairly straightforwardly. For instance if we want to declare a pointer to an integer, we simply write: int ∗ intPointer ; Or, to declare a pointer to a double, we write: d ou b le ∗ d b l P o i n t e r ; However, since functions are more complicated than simple variables, however, the declaration of a function pointer is also more complicated. Specifically, if we want to declare a pointer to be used with functions, we need to specify both the return type and argument type(s) of the kind of functions we want to be able to ‘point to’. For example, if we want to point to functions such as that declared above, we need to specify a pointer to a function which takes no arguments and returns an integer. This can be done as follows: i n t (∗ functionPointer ) ( ) ; Similarly, if we wanted to declare a pointer to a function with no return type but which takes an integer argument we would instead write:
25.1. Function Pointers
185
void (∗ fu n ction Poin ter ) ( i n t ) ; As you have probably already worked out from the above example, function pointers are declared as the return type of the functions they point to, while the contents of the 2nd set of round brackets pertains to the arguments of the functions to be ‘pointed to’ (Note: if the pointed-to functions take no arguments, the brackets are still included, but left empty, as above). The name of the function pointer (here, we have simply named our pointers ‘functionPointer’) must be contained in brackets to ensure that the function pointer is read correctly, and not interpreted as a forward declaration of a function of the same name. Below is an example of a function pointer in action: // f o r cin , cou t e t c . #i n c l u d e // d e c l a r i n g and d e f i n i n g a f u n c t i o n . . . i n t giveMeFive ( ) { return 5; } // . . . and a 2nd , s i m i l a r f u n c t i o n // with th e same argument and r e t u r n t y p e s i n t giveMeTen ( ) { return 10; } i n t main ( ) { // d e c l a r i n g a p o i n t e r , and s e t t i n g i t to ' p o i n t at ' // our ” giveMeFive ” f u n c t i o n . // Note t h a t we do not i n c l u d e th e ' ( ) ' h er e , as we // a c t u a l l y want th e memory a d d r e s s ! i n t ( ∗ f u n c t i o n P o i n t e r ) ( ) = giveMeFive ; // C a l l i n g ” giveMeFive ” u s i n g th e f u n c t i o n p o i n t e r ! s t d : : cou t << ( ∗ f u n c t i o n P o i n t e r ) ( ) << s t d : : e n d l ; // P o i n t i n g i n s t e a d at ” giveMeTen ” . . . f u n c t i o n P o i n t e r = giveMeTen ; //And c a l l i n g t h a t f u n c t i o n u s i n g th e same p o i n t e r ! s t d : : cou t << ( ∗ f u n c t i o n P o i n t e r ) ( ) << s t d : : e n d l ; // Note t h a t we can a l s o u s e our p o i n t e r l i k e t h i s : s t d : : cou t << f u n c t i o n P o i n t e r ( ) << s t d : : e n d l ; } Note that we can use function pointers to call our functions in two ways. The first, (*functionPointer)() (e.g. lines 17, 23), is an explicit dereference while the second, functionPointer() (e.g. line 25), is an implicit dereference. Both methods carry advantages and disadvantages – calling via an implicit dereference more closely resembles a ‘normal’ function call, but may not work with some older compilers. The former method meanwhile, despite looking more messy, will always work.
25.1. Function Pointers
25.1.1
186
std::functions
In C++11, we have access to std::functions, which can be used similarly to function pointers, but use a different syntax. However, these std::functions are considerably more versatile than function pointers, in that they can work with any type of callable object including both functions and, perhaps most importantly, lambda expressions – which we will discuss in the next section. The downside of std::functions is that they are relatively slow as compared to function pointers. However, as std::functions are relatively ‘new’ by C++ standards, it is likely that they will become faster in the future as their implementation is refined. An std::function is declared as follows: s t d : : f u n c t i o n name ; So, if we want to use an std::function with a function that takes an integer as an argument and returns an integer, we would write: s t d : : f u n c t i o n f n ; which is equivalent to the following function pointer: i n t (∗ fn ) ( i n t ) ; std::functions can be ‘assigned’ a function – or other object(!) – as follows: // f o r cin , cou t e t c . #i n c l u d e // f o r s t d : : f u n c t i o n #i n c l u d e // d e c l a r i n g and d e f i n i n g a f u n c t i o n . . . i n t giveMeFive ( ) { return 5; } i n t main ( ) { // a s s i g n i n g ' giveMeFive ' to th e f u n c t i o n p o i n t e r fn , // which t a k e s no arguments , but r e t u r n s an i n t s t d : : f u n c t i o n f n = giveMeFive ; // c a l l i n g ' giveMeFive ' with our s t d : : f u n c t i o n // and o u t p u t t i n g th e r e s u l t s t d : : cou t << f n ( ) << s t d : : e n d l ; } ...which, again, should seem very familiar from our introduction to function pointers! Note that, since giveMeFive takes no arguments, the ‘()’ in the std::function declaration is left empty.
25.1. Function Pointers Note also that to use std::functions, we need to use the header: #i n c l u d e
187
25.1. Function Pointers
188
Exercise 25.1. For the code below: 1. Comment the code to explain what is happening at each step. 2. Determine whether each assignment of a function pointer would successfully compile. 3. Determine what will be output to the console for each ‘std::cout’.
#i n c l u d e i n t giveMeFive ( ) { return 5; } i n t giveMeTen ( ) { return 10; } i n t timesTwo ( i n t x ) { return (x ∗ 2); } i n t plusTwo ( i n t x ) { return (x + 2); } i n t main ( ) { i n t ( ∗ f u n c t i o n P o i n t e r 1 ) ( ) = giveMeFive ; s t d : : cou t << ( ∗ f u n c t i o n P o i n t e r 1 ) ( ) << s t d : : e n d l ; f u n c t i o n P o i n t e r 1 = giveMeTen ; s t d : : cou t << ( ∗ f u n c t i o n P o i n t e r 1 ) ( ) << s t d : : e n d l ; s t d : : cou t << f u n c t i o n P o i n t e r 1 << s t d : : e n d l ; int std std std
( ∗ f u n c t i o n P o i n t e r 2 ) ( i n t ) = timesTwo ; : : cou t << f u n c t i o n P o i n t e r 2 ( 2 ) << s t d : : e n d l ; : : cou t << ( ∗ f u n c t i o n P o i n t e r 2 ) ( 2 ) << s t d : : e n d l ; : : cou t << f u n c t i o n P o i n t e r 2 ( ( ∗ f u n c t i o n P o i n t e r 2 ) ( 2 ) ) << s t d : : e n d l ;
f u n c t i o n P o i n t e r 2 = plusTwo ; s t d : : cou t << f u n c t i o n P o i n t e r 2 ( 2 ) << s t d : : e n d l ; s t d : : cou t << f u n c t i o n P o i n t e r 2 ( ( ∗ f u n c t i o n P o i n t e r 2 ) ( 2 ) ) << s t d : : e n d l ; f u n c t i o n P o i n t e r 1 = timesTwo ; s t d : : cou t << f u n c t i o n P o i n t e r 1 ( 2 ) << s t d : : e n d l ; s t d : : cou t << f u n c t i o n P o i n t e r 2 ( 2 ) << s t d : : e n d l ; } Re-write the above example using exclusively std::functions.
25.2. Lambda Functions
25.2
Lambda Functions
25.2.1
An Introduction to Lambda Functions
189
Before discussing lambda functions in detail, it is first very useful to understand inline functions and their uses. As we have covered previously, calling a ‘normal’ function requires the running program to ‘jump’ to the memory address corresponding to the function called, execute the relevant code, and then ‘jump’ back to the main function. Clearly, this is a somewhat time-inefficient process. When using an inline function, meanwhile, when the code is compiled, the function call is replaced with the function code itself. As such, when the code is actually run, there is no need to jump between different positions in the computer’s memory when using this function. Thus, inline functions are often used as an enhancement feature to improve the execution time of a program. Note, however, that using inline functions will add to the size of the exe files produced, making its widespread use unsuitable for embedded systems, for instance, where limited memory is an issue. Any function can be ‘made inline’ simply by using the inline keyword; for example: i n l i n e i n t plusTwo ( i n t x ) { return (x + 2); } In fact, even if a function is not explicitly declared inline, the compiler may – in certain circumstances – decided to make a non-inline function inline if it determines that this would make the code more efficient. Lambda functions are a particularly useful type of inline function. The generic definition of a lambda function is as follows: typ e n a m e o f f u n c t i o n [ c a p t u r e s p e c i f i c a t i o n ] ( arguments ){ methods } So, a very simple lambda function might look something like this: auto s a y H e l l o = [ ] ( ) { s t d : : cou t << ” H e l l o World” << s t d : : e n d l ; } ; Note the use of the auto keyword to automatically determine the type of the lambda function. The capture specification, ‘[]’, at the start of the above code snippet acts as an identifier that lets the compiler know that we are declaring a lambda function. Our function, ‘sayHello’, requires no arguments, so the round brackets, ‘()’, which would normally hold the arguments
25.2. Lambda Functions
190
of a lambda function, are left empty. A final interesting thing to note about lambda functions is that we do not need to specify a return type – the compiler can work that out for us! Calling a lambda function is more-or-less as simple as calling a normal function. If we want to call the above lambda, we simply write: sayHello ( ) ; in our main function, and the lambda function will be called, in our case simply outputting to screen the now familiar “Hello World” message. Of course, this is a very trivial example, and does not require the use of lambda functions. In the next section, we will see the true power of lambda functions.
25.2.2
Lambdas in Action – Making a DIY CTRL+F
Lambda functions are – to put it lightly – not a trivial thing to understand and, moreover, they perform a lot of different functions. This being the case, the best way to teach lambda functions is not to talk about them, but to show them working. In this section, we will teach you some of the more complex uses of lambda functions through an extended example. The code below implements lambda functions in a code which acts to look for, and return, strings containing a certain character or sequence of characters. Such a code might, for instance, form the basis of an operating system’s file search mechanism, and it is in this context that we present the code. The code also draws together many of the other more complex concepts we have come across during the course – for example templates, classes and iterators – and, as such, should also help us solidify our knowledge of these.
#i n c l u d e #i n c l u d e #i n c l u d e <s t r i n g > // d e f i n i n g a c l a s s c a l l e d ” f i l e F o l d e r ” class fileFolder { private : //The ( p r i v a t e ) f i l e s s t o r e d i n our f i l e F o l d e r . // S i n c e t h i s i s j u s t a s i m p l e example , th e f i l e s a r e ” hardcoded ” // i n t o th e c l a s s , but c o u l d e a s i l y be made c h a n g e a b l e // by i n c l u d i n g a ” s e t ” f u n c t i o n i n our c l a s s . s t d : : v e c t o r <s t d : : s t r i n g > f i l e s = { ” t e x t F i l e . t x t ” , ” code . cpp” , ” p r e s e n t a t i o n . pdf” , ” researchPaper . pd ” p r a c t i c e . cpp ” , ” n o t e s . t x t ” , ” book . p d ”document . t x t ” , ” moreNotes . t x t ” } ; public : // c r e a t i n g a t e m p l a t e f u n c t i o n with th e p l a c e h o l d e r name ” Fu n ction ” // to remind us th at , f o r th e c u r r e n t problem , th e typ e w i l l alw ays // be some form o f f u n c t i o n t e m p l a t e
25.2. Lambda Functions
191
// d e c l a r i n g a tem p lated f u n c t i o n with a r e t u r n typ e t h a t i s // a v e c t o r o f s t d : : s t r i n g s . //The tem p lated f u n c t i o n i t s e l f w i l l r ead i n a f u n c t i o n ” s e a r c h F u n c t i o n ” . s t d : : v e c t o r <s t d : : s t r i n g > f i n d F i l e ( Fu n ction s e a r c h F u n c t i o n ) { // d e c l a r i n g an empty v e c t o r named ” s e a r c h R e s u l t s ” t h a t w i l l , as // th e name s u g g e s t s , s t o r e our e v e n t u a l s e a r c h r e s u l t s ! s t d : : v e c t o r <s t d : : s t r i n g > s e a r c h R e s u l t s ;
f o r ( auto i t r = f i l e s . b e g i n ( ) , end = f i l e s . end ( ) ; i t r != end ; ++i t r ) // Checks i f our ( c u r r e n t l y unknown) s e a r c h f u n c t i o n r e t u r n s ' t r u e // f o r th e elem en t o f th e ” f i l e s ” v e c t o r c u r r e n t l y b e i n g p o i n t e d t i f ( searchFunction ( ∗ i t r )) { // I f our ( unknown) s e a r c h f u n c t i o n r e t u r n s ' t r u e ' , i . e . i f //we have found a match , i n s e r t s th e s t d : : s t r i n g c o r r e s p o n d i n // to th e c u r r e n t elem en t i n t o our ” s e a r c h R e s u l t s ” v e c t o r a r r a s e a r c h R e s u l t s . p u s h b ack ( ∗ i t r ) ; } } // r e t u r n s a l l s u c c e s s f u l matches ! return searchResults ; };
}
i n t main ( ) { // D e c l a r i n g an i n s t a n c e o f th e ” f i l e F o l d e r ” c l a s s . f i l e F o l d e r myFolder ; // d e c l a r i n g a v e c t o r o f s t d : : s t r i n g s to s t o r e our s e a r c h r e s u l t s s t d : : v e c t o r <s t d : : s t r i n g > myResults ; // c a l l i n g th e ” f i n d F i l e ” f u n c t i o n from our i n s t a n c e o f th e // ” f i l e F o l d e r ” c l a s s and p a s s i n g i s a ∗∗ lambda f u n c t i o n ∗∗ as an // argument . myResults = myFolder . f i n d F i l e ( //Our lambda f u n c t i o n l o o k s f o r th e s e q u e n c e o f c h a r a c t e r s ” . t x t ” // i n any s t d : : s t r i n g s p a s s e d to i t −− i n t h i s c a s e th e c o n t e n t s // o f ” myFolder ” ' s ” f i l e s ” v e c t o r . // I f th e r e l e v a n t s t r i n g i s ( . t x t ) i s found , th e lambda w i l l // r e t u r n ” t r u e ” and ” f i n d F i l e ” w i l l add th e r e l e v a n t s t d : : s t r i n g // to th e ” s e a r c h R e s u l t s ” v e c t o r . [ ] ( c o n s t s t d : : s t r i n g& f i l e N a m e ) { r e t u r n f i l e N a m e . f i n d ( ” . t x t ” ) != s t d : : s t r i n g : : npos ; } ); // o u t p u t s our s e a r c h r e s u l t s to th e c o n s o l e ! f o r ( i n t i = 0 ; i < myResults . s i z e ( ) ; i ++) { s t d : : cou t << myResults [ i ] << s t d : : e n d l ; } return 0; }
25.2. Lambda Functions
192
Despite being heavily commented, it is still worth explaining the above code step-by-step to provide both a clearer overview of the code’s function, as well as a few extra details, tricks and tips. We start off by creating a class ‘fileFolder’. Any instance of this class will possess: 1. A vector of strings (‘files’) containing a series of hypothetical file names. 2. A templated function (‘findFile’) which takes as an argument some unknown function (‘searchFunction’). ‘findFile’ uses iterators to look through all elements contained in the ‘files’ vector array, passing each element to the unknown function. If this function returns ‘true’ for a given element, it is added to the ‘searchResults’ list. When the ‘findFile’ reaches the end of the ‘files’ vector, the ‘searchResults’ vector is returned. So, our ‘fileFolder’ class contains everything we need to perform a ‘CTRL+F’-style search through our stored ‘files’ – except for a function which actually establishes whether a given std::string from the ‘files’ vector matches our search criteria! This is where our lambda function comes in. In our main() function, we create an instance of our ‘fileFolder’ class (‘myFolder’) and pass a lambda function to the ‘findFile’ member function, where it takes on the rˆ ole of ‘searchFunction’. Our lambda function: [ ] ( c o n s t s t d : : s t r i n g& f i l e N a m e ) { r e t u r n f i l e N a m e . f i n d ( ” . t x t ” ) != s t d : : s t r i n g : : npos ; } simply takes as an argument a string (‘fileName’) and uses the std::string’s inbuilt ‘find()’ operation to search for the sequence of characters ‘.txt’. The function returns ‘true’ if the character sequence is successfully found (or, more specifically to the syntax used, if the sequence is not not found!)1 . The elements of the ‘files’ vector for which our lambda function returns ‘true’ will then be added to the vector which stores our successful search results. Note that we do not have to bother explicitly defining our lambda as a bool – the return type of a lambda is deduced from return statements (lambdas effectively have a built-in ’auto’ !). Nonetheless, if desired (or if our lambda contains multiple statements, which may confuse our compiler), it is also possible to explicitly specify the type of a lambda. This is done simply by adding ‘-> Type’ after the arguments brackets, (), but before the methods, {}. So, in our above example, if we wanted (for peace of mind, perhaps) to explicitly declare the return type of our lambda as a bool, we would simply need to write: [ ] ( c o n s t s t d : : s t r i n g& f i l e N a m e ) −> b o o l { . . . } Try running the code from the start of the section again, but this time replace the lambda function with the above; you will notice that, as expected, it makes absolutely no difference! 1 The ‘find()’ function returns the string ‘npos’ if no matches are found in the string being searched, i.e. fileName.find( ".txt" ) != std::string::npos will return true if a match is found.
25.2. Lambda Functions
193
Although the above example demonstrates one strength of lambdas – that they can be easily passed as functions to other functions – the code could (almost) as easily be written without using a lambda function. To really illustrate the beauty of lambdas, we need to show the capture specifier in action. Below, we show a slightly modified version of the main() function from our previous example: i n t main ( ) { // d e c l a r i n g and r e a d i n g i n a s t d : : s t r i n g ` searchTerm ' , a l l o w i n g // th e u s e r to s p e c i f y th e s e q u e n c e to be s e a r c h e d f o r . s t d : : s t r i n g searchTerm ; s t d : : cou t << ” Find : ” ; s t d : : c i n >> searchTerm ; f i l e F o l d e r myFolder ; s t d : : v e c t o r <s t d : : s t r i n g > myResults ; myResults = myFolder . f i n d F i l e ( // M o d i f i e d lambda f u n c t i o n now ` c a p t u r e s ' th e u s e r i n p u t ! [ & ] ( c o n s t s t d : : s t r i n g& f i l e N a m e ){ r e t u r n f i l e N a m e . f i n d ( searchTerm ) != s t d : : s t r i n g : : npos ; } ); f o r ( i n t i = 0 ; i < myResults . s i z e ( ) ; i ++) { s t d : : cou t << myResults [ i ] << s t d : : e n d l ; } return 0; } In the above, we adapt our program so that instead of using a ‘search term’ that is hard-coded, we instead allow the user to choose what to search for. Let’s take a closer look at our ‘revised’ lambda function: [ & ] ( c o n s t s t d : : s t r i n g& f i l e N a m e ){ r e t u r n f i l e N a m e . f i n d ( searchTerm ) != s t d : : s t r i n g : : npos ; } Unlike the original version, we now have an ‘& ’ symbol in our capture specifier. This tells our compiler that we want our lambda function to have variable capture. By including this capture specifier, we can use the ‘searchTerm’ variable inside our lambda even though it is not declared within the function! Note that using ‘&’ captures all variables and captures them by reference (variables can also be captured by value by replacing ‘&’ with ‘=’). It is additionally useful to know that lambdas can also capture a specific variable. For instance, instead of using ‘& ’ in our example, we could instead have written: [& searchTerm ] ( c o n s t s t d : : s t r i n g& f i l e N a m e ){ r e t u r n f i l e N a m e . f i n d ( searchTerm ) != s t d : : s t r i n g : : npos ;
25.2. Lambda Functions
194
} This more specific capture specifier may be valuable, for instance, in situations where a large number of variables would be captured using the more general specifiers (‘&’ or ‘=’), potentially slowing down the resultant code. It is also possible to capture multiple variables using a commaseparated list – just like in the arguments of normal functions. In order to provide a complete background to lambda functions, we need to introduce one final capture specifier – ‘this’. When inside a C++ object, the ‘this’ keyword corresponds to a pointer which stores the address of the current object. In other words, a ‘this’ inside an instance of a class (for example) provides a pointer to the instance itself. As usual, these things are much more easily explained using an example: #i n c l u d e // d e f i n i n g a c l a s s ' U s e l e s s C l a s s ' class UselessClass { public : // d e f i n i n g a p u b l i c member v a r i a b l e , ' v a r i a b l e ' , // o f th e b o o l e a n typ e bool v a r i a b l e = true ; // d e f i n i n g a p u b l i c member f u n c t i o n , ' u s e l e s s F u n c t i o n ' void u selessFu n ction ( bool v a r i a b l e ) { // o u t p u t s th e b o o l ' v a r i a b l e ' p a s s e d to // th e f u n c t i o n s t d : : cou t << v a r i a b l e << s t d : : e n d l ; // o u t p u t s th e b o o l ' v a r i a b l e ' which // ∗∗ b e l o n g s to ” t h i s ” c l a s s ∗∗ s t d : : cou t << t h i s −>v a r i a b l e << s t d : : e n d l ; } }; i n t main ( ) { // d e f i n i n g an i n s t a n c e o f our U s e l e s s C l a s s // and c a l l i n g i t , s u i t a b l y , u s e l e s s I n s t a n c e UselessClass uselessInstance ; // c a l l i n g th e u s e l e s s F u n c t i o n f u n c t i o n // f o r th e c u r r e n t i n s t a n c e o f U s e l e s s C l a s s // and p a s s i n g i t a ' f a l s e ' b o o l e a n . uselessInstance . uselessFunction ( f a l s e ) ; return 0; } Of course, as is often the case with these simple examples, the above code is highly unlikely to be practically useful, but nonetheless illustrates what the ‘this’ pointer does! The code, when compiled and run, will output: 0 (false)
25.2. Lambda Functions
195
1 (true) But why? The first method of our ‘uselessFunction’ does what most of us would likely expect for a normal function of the form: void ( bool x ) { s t d : : cou t << x ; } In the second method, however, the ‘this’ keyword comes in to play. As we have just learned, ‘this’ provides a pointer to an object, in this case an instance (uselessInstance) of our class (UselessClass). As such, when we call ‘this->variable’, we are specifically instructing our compiler to give us the version of variable which belongs to uselessInstance – i.e. the member variable of UselessClass – not the one read in from outside! From this example, we can now see that the ‘this’ pointer gives us access to all the member variables and functions associated with an object, and hence how it may be useful for a lambda function to be able to capture the ‘this’ pointer. Below, we give an example demonstrating the same point, but this time actually using lambda functions and their capture specifiers: #i n c l u d e class UselessClass { public : bool v a r i a b l e = true ; void thisFunc ( ) { // lambda f u n c t i o n u s i n g ' t h i s ' as a c a p t u r e s p e c i f i e r [ this ](){ s t d : : cou t << v a r i a b l e << s t d : : e n d l ; } (); // n ote th e i n c l u s i o n o f a s econ d ' ( ) ' at th e end o f th e // lambda − t h i s means t h a t th e f u n c t i o n w i l l a c t u a l l y // be c a l l e d when ' t h i s F u n c ' i s c a l l e d . } v o i d thatFunc ( b o o l v a r i a b l e ) { // an i d e n t i c a l lambda f u n c t i o n ∗∗ e x c e p t ∗∗ // u s i n g th e '= ' c a p t u r e s p e c i f i e r [=](){ s t d : : cou t << v a r i a b l e << s t d : : e n d l ; } (); } }; i n t main ( ) { UselessClass uselessInstance ; u s e l e s s I n s t a n c e . thisFunc ( ) ; u s e l e s s I n s t a n c e . thatFunc ( f a l s e ) ; return 0; }
25.2. Lambda Functions
196
Just like the previous example, the above code will output: 0 (false) 1 (true) i.e. the function ‘thisFunc’ (where our lambda uses the ‘this’ capture specifier) will return true, while ‘thatFunc’ (which takes the ‘=’ access specifier) will return false. This also shows us a valuable piece of information about the ‘=’ (and similarly &) capture specifiers – if two versions of a variable with the same name exist, they will capture the variable in the nearest scope (we put this concept to the test in the exercises at the end of the section!). Make an example showing that = will look within the closest scope – i.e. show an example using ”variable” or something else and show that it then looks to the rest of the class and captures the first thing it seems called variable!
25.2.3
Summary of Capture Specifiers
Since the last section was rather weighty, we include here a more concise summary of the various different capture specifiers used with lambda functions. Capture Specifier &var var var1, var2, var3... & = [empty] this
Explanation Capture a single variable, ‘var’, by reference. Capture a single variable by value (i.e. make a ‘copy’). Capture multiple specified variables. Capture all variables by reference. Capture all variables by value. Capture nothing. Capture the ‘this’ pointer (when in a class).
25.2. Lambda Functions
197
Exercise 25.2. Spot the mistake: the code below, which you have already seen in the preceding chapter, contains a deliberate mistake, the kind of typographical mistake one can easily make when coding! What would the output of this code be, and why? #i n c l u d e class UselessClass { public : bool v a r i a b l e = true ; void thisFunc ( ) { [ this ](){ s t d : : cou t << v a r i a b l e << s t d : : e n d l ; } (); } v o i d thatFunc ( b o o l v a r i a b l e ) { [=](){ s t d : : cou t << v a r i a b l e << s t d : : e n d l ; } (); } }; i n t main ( ) { UselessClass uselessInstance ; u s e l e s s I n s t a n c e . thisFunc ( ) ; u s e l e s s I n s t a n c e . thatFunc ( f a l s e ) ; return 0; } As you have probably already worked out, one of the (many) values of lambdas is that they do not need to be declared and named like ‘normal’ functions. The simple code below uses the very useful for each2 function to print a tab-separated list of all the elements in a vector. However, this code can be re-written much more concisely and efficiently using a lambda function. In fact, lines 6, 7, 8 and 15 can all be combined into a single line of code! Give it a go! #i n c l u d e // f o r s t d : : f o r e a c h #i n c l u d e #i n c l u d e // D e f i n i n g a f u n c t i o n to p r i n t tab−s e p a r a t e d l i s t s void tabSepPrint ( i n t i ) { s t d : : cou t << i << ' \ t ' ; } i n t main ( ) { // d e c l a r i n g an a r b i t r a r y v e c t o r to p r i n t s t d : : v e c t o r v = { 1 , 2 , 3 , 4 , 5 } ; // u s i n g th e f o r e a c h f u n c t i o n to p a s s a l l e l e m e n t s 2
The for each function is an easy way to apply a function to multiple elements of a given container. It takes three arguments: the first and last elements to which we want to apply the function, and the function we want to apply. Each of the elements between the chosen start- and end-point are then passed as the argument of the function provided.
25.2. Lambda Functions
198
// o f v ( i . e . s t a r t i n g at v . b e g i n ( ) and en d in g // at v . end ( ) ) i n tu r n to th e ” t a b S e p P r i n t ” f u n c t i o n f o r e a c h ( v . b e g i n ( ) , v . end ( ) , t a b S e p P r i n t ) ; return 0; } Some practice with ‘this’: In this exercise, we are going to use the ‘this’ keyword to create the template for a ‘Top Trumps’-like game. The game should be able to compare the attributes of different objects of the same class and decide which one ‘wins’. Some example code is given below to get you started, but you do not have to follow the same structure; this example uses cars, but you can try with anything you want, and add as many features to the game as you like! #i n c l u d e #i n c l u d e <s t r i n g > c l a s s Car { public : // d e f i n i n g some v a r i a b l e s to r e p r e s e n t c h a r a c t e r i s t i c s // t h a t may be im p or tan t i n a c a r ! d ou b le topSpeed ; d ou b le bhp ; d ou b le zeroToSixtyTime ; // J u s t some i d e a s − // you c o u l d add as many more as you l i k e ! //The name f o r each i n s t a n c e − i . e . your model o f c a r ! s t d : : s t r i n g model ; // c r e a t i n g a c o n s t r u c t o r which a l l o w s us to // e a s i l y and q u i c k l y e n t e r th e d e t a i l s o f our c a r s ! Car ( d ou b le speed , d ou b le acc , s t d : : s t r i n g name ) { topSpeed = s p eed ; zeroToSixtyTime = a c c e l e r a t i o n ; model = name ; } // This f u n c t i o n s h o u l d d e t e r m i n e which c a r has // th e h i g h e r top s p eed and d e c l a r e an a p p r o p r i a t e // ” winner ” . v o i d i s F a s t e r ( Car c a r ) { // [YOUR CODE HERE ! ] } // . . . // . . . }; i n t main ( ) { // C r e a t i n g some ”Car”−typ e o b j e c t s . Car p o r s c h e ( 3 5 1 . 0 , 2 . 2 , ” P or s ch e 918 ” ) ; Car b u g a t t i ( 4 0 8 . 8 4 , 2 . 5 , ” B u g a t t i Veyron” ) ; // c a l l i n g th e ” i s F a s t e r ” f u n c t i o n b u gatti . i s F a s t e r ( porsche ) ; // i f your f u n c t i o n i s defined correctly ,
25.2. Lambda Functions // both c o m b i n a t i o n s s h o u l d // g i v e th e same r e s u l t ! porsche . i s F a s t e r ( b u gatti ) ; return 0; }
199
Chapter 26 Literature and longer exercises
26.1
Further reading
The many new terms used in the last pages indicates that C++ has much more possibilities, rules and options to be explored. Classes, templates, over-loading, scopes, etc. can not be discussed in this short course. However, here is a list of further literature:
1. Wikipedia ... 2. Brian W. Kernighan and Dennis M. Ritchie, The C-Programming Language, 2nd edition, Prentice Hall, 1988. 3. B. Stroustrup, The C++ Programming Language, 3rd edition, Addison Wesley, 1997. 4. Steve Ouallinie, Practical C++ Programming, O’Reilly, 1995. 5. C. S. Horstmann, Mastering C++, John Wiley & Sons, New York, 1996. 6. S. B. Lippman, C++ Einf¨ uhrung und Leitfaden, 3. Auflage, Addison-Wesley, Bonn, 1998.
– 200 –
26.2. Longer exercises C++
26.2
201
Longer exercises C++
Exercise 1 Describe with a few words what the following program is doing. Do not copy this file into your computer - solve this by reading it and write a few sentences (in 15 minutes). Then plot a flow-chart or flow-diagram. #i n c l u d e #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( i n t ar gc , ch ar ∗ ar gv [ ] ) { // D e f i n e f i e l d x ( t ) with l e n g t h 1000 d ou b le x [ 1 0 0 0 ] , t ; // ou tp u t v a r i a b l e s // i n i t i a l c o n d i t i o n s d ou b le A, d e l t a ; // A=amplitude , d e l t a=phase−a n g l e d ou b le mass , ks p r n g ; // mass=mass , ks p r n g=s p r i n g−c o n s t a n t d ou b le t max , dt ; // t max=max−time , dt=time−i n t e r v a l l // Request i n p u t o f th e p a r a m e t e r s cou t << ” am p litu d e ” ; c i n >> A; cou t << ” phase−a n g l e ” ; c i n >> d e l t a ; cou t << ” mass ” ; c i n >> mass ; cou t << ” s p r i n g−c o n s t . ” ; c i n >> ks p r n g ; cou t << ”max−time ” ; c i n >> t max ; cou t << ” time−i n t e r v a l ” ; c i n >> dt ; d ou b le omega=s q r t ( ks p r n g / mass ) ; // Loop from t=0 to t=t max t =0.0; f o r ( i n t i =0; i<=t max / dt ; i++ ) { x [ i ]=A∗ s i n ( omega ∗ t+d e l t a ) ; // Compute f u n c t i o n t=t+dt ; // Step to n ext time }
}
o f s t r e a m o u t f i l e ( ” p l o t . data ” ) ; // Output to f i l e t =0.0; f o r ( i n t i =0; i<=t max / dt ; i++ ) { o u t f i l e << t << ” ” << x [ i ] << ” \n” ; t=t+dt ; }
26.2. Longer exercises C++
202
Exercise 2 Writing the first program. Extend the minimal, basic C++ program by the command lines int inum=0; cin >> inum; where the second requests input of an integer number from the keyboard. Write a C++ program that prints the binary representation of the integer number inum to the screen. You can check if the program works by, e.g., using the number 496 from the lectureexample.
Exercise 3 What is the greatest value of n that can be used in the sum 12 + 22 + 32 + . . . + n2 and gives a total value of the sum less than 100? (a) Write a short C++ program that answers this question – like in the Matlab exercise ?? Then answer the question also for an exponent of 10 and a total value of the sum of (b) less than 106 and (c) less than 1012 (Advanced). (d) If doing both parts compare the run-time between you C++ and MATLAB implementation.
Exercise 4 Declare an array with 10 001 entries. Compute the solution vector f (xi ), with xi = 0, . . . , 10 000 (as fast as possible!) f (xi ) =
xi sin(xi ) + 2
In the same program, form the alternating sum Sn = f (x0 ) + f (x1 ) − f (x2 ) + f (x3 ) − . . . up to the last term and print the result to the screen. Finally, compare the result with the result obtained in the Matlab section ??.
26.2. Longer exercises C++
203
Exercise 5 In the following program (part of which we have discussed today) there are hidden 10 syntax and typo-errors. See how many you can find in 5-10 minutes. #i n c l u d e #i n c l u d e #i n c l u d e u s i n g namespce s t d ; i n t main ( i n t ar gc , ch ar ∗ ar gv [ ] ) { int i ; i n t n=5; i n t ∗p ; int a [ 1 0 ] ; f o r ( i =0; i <=10; i++ } a [ i ]=10; p [ i ]=10; cou t << cou t << cou t << cou t << cou t << cou t << cou t << cou t << i=n+1; cou t << p=&n ; cou t << ∗p+=2 cou t << p++; cou t <<
a << ” \n” ; ∗a << ” \n” ; ∗ ( a ) << ” \n” ; a [ 1 ] << ” \n” ∗ ( a+2) << ” \n” ; s i z e o f ( i n t ) << ” ” << s i z e o f f ( i n t ∗ ) << ” \n” ; s i z e o f ( d ou b le ) << ” ” << s i z e o f f ( d ou b le ∗ ) << ”\n” ; ” n : ” << n << ” ” << &n << ” \n” ; ” i : ” << i << ” ” << &i << ” \n” ; ” p : ” << p << ” ” << ∗p << ” \n” ; ” p : ” << p << ” ” << ∗p << ” \n” ; ” p : ” << p << ” ” << &p << ” \n” ;
return 0; }
26.2. Longer exercises C++
204
Exercise 6 This is an example of pointers: (a) Use the following program segment and play around using the pointers. #i n c l u d e #i n c l u d e #i n c l u d e u s i n g namespace s t d ; i n t main ( i n t ar gc , ch ar ∗ ar gv { ch ar c= ' x ' ; int a [ 2 0 ] ; i n t ∗p = a ; // ok , // // i n t ∗p = &(a [ 0 ] ) ; // . . . p [ 5 ] = 4;
// // a [ 5 ] = 4; // // int b [ 2 0 ] [ 3 0 ] ; // // // // int ∗r = b [ 0 ] ; // // i n t (∗ q ) [ 3 0 ] = b ; // // q [ 1 2 ] [ 1 5 ] = 26; // ( ∗ ( q + 1 2 ) ) [ 1 5 ] = 2 6 ; // ∗ ( ∗ ( q+12)+15) = 2 6 ; // b [ 1 2 ] [ 1 5 ] = 26; //
[])
a i s name o f th e f i e l d and can be used as a d d r e s s to th e f i e l d e q u i v a l e n t ( e r r o r −>r e d e c l a r a t i o n )
a c c e s s to a th r ou gh p o i n t e r a r i t h m e t i c , a [ 5 ] i s s e t to th e v a l u e o f 4 . . . equivalent b i s now an a r r a y o f 20 a r r a y s o f 30 e l e m e n t s o f typ e i n t i n t ∗p = b ; e r r o r ! wrong type , s i n c e b i s o f typ e p o i n t e r to 30 i n t h e r e ok , r p o i n t s to th e f i r s t i n t i n th e f i r s t ( o f 20) a r r a y ( s ) o f 30 i n t s ok , q p o i n t s to th e f i r s t s e t o f 30 i n t ' s , q and b can now be used synonymous ok , s e t elem en t ( 1 3 , 1 6 ) to th e v a l u e 26 . . . equivalent . . . equivalent . . . equivalent
cou t . put ( c ) ; int ∗ p i = new i n t ; // Person ∗ p p = new Person (”B . S t r o u s t r u p ” , 4 5 ) ; int n = 40; int ∗ p a i = new i n t [ n ] ; // . . . delete p i; // delete p p; delete [ ] pa i ; // // pa i [0]=5; pa i [1]=4;
26.2. Longer exercises C++
205
f o r ( i n t i =0; i <10; i ++) cou t << p a i [ i ] << ' ' ; return 0; } Serious programming exercise: Define an int field (vector) that contains the numbers: { 1, 0, -10, 12, -2, 5, 5, 1, -4, -2, -4, -8, 3, 25, 51, -4, -5 } Then sort the entries of this linear field/vector. (b) Read the field from a file. (c) Use a linked-list to store the field. (d) Implement a linked list (with pointers) to store the field. (e) Use this linked list (with pointers) to sort the field. (f) Write the sorted list to an output file, but remove double entries from the list. What is the length of the field before and after this sorting/remove operation? (g) (Advanced) Implement a (heap) tree structure to sort the field such that the largest entry is always on top of the tree.
Exercise 7 Write a root-finding function in C++ and apply to general fifth order equation of your choice. (Advanced)