Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Ashok Kumar, Bharath
so2021
Commits
f3fb9168
Commit
f3fb9168
authored
May 12, 2021
by
Praetorius, Simon
Browse files
section about includes and libraries added
parent
d6b09aa6
Changes
18
Hide whitespace changes
Inline
Side-by-side
presentation/_includes/advanced-datatypes.md
View file @
f3fb9168
...
...
@@ -10,8 +10,8 @@ Often you do not always want to care about the actual datatype used in your prog
do this via
`typedef`
/
`using`
:
```
c++
typedef
<
type
>
<
alias_name
>
;
using
<
alias_name
>
=
<
type
>
;
//
<
suggested
typedef
<
type
>
<
alias_name
>
;
// or...
using
<
alias_name
>
=
<
type
>
;
//
(
suggested
)
```
Afterwards,
`<alias_name>`
can be used like any other datatype:
...
...
@@ -137,7 +137,7 @@ The individual variables in a struct are accessed via `.` operator, i.e.:
```
c++
Vector
x
;
x
.
size
=
10
;
x
.
size
=
10
;
x
.
data
=
new
real_t
[
x
.
size
];
```
...
...
@@ -229,9 +229,10 @@ Here, only a single pointer is supplied to the function instead of 200
---
# Advanced Datatypes
## Array
s
of Struct
## Array of Struct
s
Like any other datatype, structs can also be allocated in the form of an array:
.pure-g[.pure-u-2-5[.padding-5[
```
c++
struct
Coord
{
real_t
x
,
y
,
z
;
...
...
@@ -239,38 +240,91 @@ struct Coord {
Coord
coordinates
[
10
];
```
]].pure-u-3-5[.padding-5[
```
c++
#include
<cmath>
...
for
(
std
::
size_t
i
=
0
;
i
<
10
;
++
i
)
{
coordinates
[
i
].
x
=
std
::
cos
(
i
*
36
*
M_PI
/
180.0
);
coordinates
[
i
].
y
=
std
::
sin
(
i
*
36
*
M_PI
/
180.0
);
coordinates
[
i
].
z
=
i
/
10.0
;
}
```
]]]
for fixed sized array or
for fixed sized array or
...
---
# Advanced Datatypes
## Array of Structs
Like any other datatype, structs can also be allocated in the form of an array:
.pure-g[.pure-u-2-5[.padding-5[
```
c++
Coord
*
coordinates
=
new
Coord
[
10
];
struct
Coord
{
real_t
x
,
y
,
z
;
};
Coord
*
coordinates
=
new
Coord
[
10
];
```
]].pure-u-3-5[.padding-5[
```
c++
#include
<cmath>
...
for
(
std
::
size_t
i
=
0
;
i
<
10
;
++
i
)
{
coordinates
[
i
].
x
=
std
::
cos
(
i
*
36
*
M_PI
/
180.0
);
coordinates
[
i
].
y
=
std
::
sin
(
i
*
36
*
M_PI
/
180.0
);
coordinates
[
i
].
z
=
i
/
10.0
;
}
```
]]]
using dynamic memory management.
...
using dynamic memory management.
---
# Advanced Datatypes
## Arrays of Structs
The access to struct members then comes after addressing the array entry:
## Struct of Arrays
The storage can also be inverted. Instead of an array of structures (AoS) one can store a structure
of arrays (SoA):
.pure-g[.pure-u-2-5[.padding-5[
```
c++
struct
Coordinates
{
real_t
x
[
10
];
real_t
y
[
10
];
real_t
z
[
10
];
};
Coordinates
coordinates
;
```
]].pure-u-3-5[.padding-5[
```
c++
#include
<cmath>
...
for
(
std
::
size_t
i
=
0
;
i
<
10
;
++
i
)
{
coordinates
[
i
]
.
x
=
std
::
cos
(
real_t
(
i
)
*
36.0
*
M_PI
/
180.0
);
coordinates
[
i
]
.
y
=
std
::
sin
(
real_t
(
i
)
*
36.0
*
M_PI
/
180.0
);
coordinates
[
i
]
.
z
=
real_t
(
i
)
/
10.0
;
coordinates
.
x
[
i
]
=
std
::
cos
(
i
*
36
*
M_PI
/
180.0
);
coordinates
.
y
[
i
]
=
std
::
sin
(
i
*
36
*
M_PI
/
180.0
);
coordinates
.
z
[
i
]
=
i
/
10.0
;
}
```
]]]
For different applications and usage/access pattern either the one or the other representation might be
more efficient or convenient.
See also https://en.wikipedia.org/wiki/AoS_and_SoA
---
# Advanced Datatypes
Structures can be nested, i.e., a struct can be a member of another struct:
## Example: Sparse Matrix in Coordinate Format
## Example
1
: Sparse Matrix in Coordinate Format
```
c++
struct
Triple
{
std
::
size_t
row
;
...
...
@@ -293,30 +347,30 @@ struct SparseMatrix {
---
# Advanced Datatypes
## Example: Sparse Matrix in Coordinate Format
Laplac
e 5
-point stencil
## Example
1
: Sparse Matrix in Coordinate Format
1d
Laplac
ian 3
-point stencil
\[
A =
\b
egin{pmatrix}
4
& -1 & & & &
\\
-1 &
4
& -1 & & &
\\
2
& -1 & & & &
\\
-1 &
2
& -1 & & &
\\
& -1 &
\d
dots & & &
\\
& & -1 &
4
& -1
\\
& & &-1 &
4
& & -1 &
2
& -1
\\
& & &-1 &
2
\e
nd{pmatrix}
\]
---
# Advanced Datatypes
## Example: Sparse Matrix in Coordinate Format
## Example
1
: Sparse Matrix in Coordinate Format
The nested structures can be initialized directly using nested curly braces:
```
c++
SparseMatrix
mat
{
10
,
10
,
{
28
,
new
Triple
[
28
]}};
std
::
size_t
idx
=
0
;
mat
.
nonzeros
.
data
[
idx
++
]
=
{
0
,
0
,
4
.0
};
mat
.
nonzeros
.
data
[
idx
++
]
=
{
0
,
0
,
2
.0
};
for
(
std
::
size_t
i
=
1
;
i
<
10
;
++
i
)
{
mat
.
nonzeros
.
data
[
idx
++
]
=
{
i
,
i
,
4
.0
};
mat
.
nonzeros
.
data
[
idx
++
]
=
{
i
,
i
,
2
.0
};
mat
.
nonzeros
.
data
[
idx
++
]
=
{
i
-
1
,
i
,
-
1.0
};
mat
.
nonzeros
.
data
[
idx
++
]
=
{
i
,
i
-
1
,
-
1.0
};
}
...
...
@@ -326,7 +380,7 @@ assert(idx == 28);
---
# Advanced Datatypes
## Example: Sparse Matrix in Coordinate Format
## Example
1
: Sparse Matrix in Coordinate Format
### Matrix-Vector product
```
c++
void
mat_vec
(
real_t
const
alpha
,
...
...
@@ -335,9 +389,9 @@ void mat_vec(real_t const alpha,
Vector
&
y
)
{
for
(
std
::
size_t
i
=
0
;
i
<
A
.
nonzeros
.
size
;
++
i
)
{
auto
const
&
entry
=
A
.
nonzeros
[
i
];
auto
const
&
[
row
,
col
,
value
]
=
A
.
nonzeros
[
i
];
// structured binding also for structs
y
[
entry
.
row
]
+=
alpha
*
entry
.
value
*
x
[
entry
.
col
];
y
[
row
]
+=
alpha
*
value
*
x
[
col
];
}
}
```
...
...
@@ -346,12 +400,12 @@ void mat_vec(real_t const alpha,
# Advanced Datatypes
## Example2: Sparse Matrix in Compressed Format
We can store sparse matrices even
more memory efficient,
with more locality
. T
hree arrays:
We can store sparse matrices even with more locality
, using t
hree arrays:
-
`indices`
: stores column indices for all entries, sorted by row,
-
`values`
: stores all coefficients in same order as in
`
col
ind`
and
-
`values`
: stores all coefficients in same order as in
`ind
ices
`
and
-
`offset`
: stores at
`offset[i]`
the position of the first value corresponding to row
`i`
in the arrays
`indices`
and
`values`
. The last field
,
contains the number of nonzeros.
`indices`
and
`values`
. The last field contains the number of nonzeros.
This format is known as the
*compressed row storage*
format.
...
...
@@ -364,6 +418,8 @@ struct CRSMatrix {
};
```
See, e.g., Y. Saad: Iterative methods for sparse linear systems, Section 2.3 Storage Schemes
---
# Advanced Datatypes
...
...
@@ -381,9 +437,9 @@ For the matrix
the corresponding source code is:
```
c++
std
::
size_t
offset
[]
=
{
0
,
2
,
4
,
7
,
9
};
// accumulated n
r
of entries per row
std
::
size_t
indices
[]
=
{
0
,
2
,
1
,
3
,
0
,
1
,
2
,
0
,
3
};
real_t
values
[]
=
{
1
,
3
,
2
,
-
1
,
-
4
,
-
1
,
1
,
1
,
3
};
std
::
size_t
offset
[]
=
{
0
,
2
,
4
,
7
,
9
};
// accumulated n
um
of entries per row
std
::
size_t
indices
[]
=
{
0
,
2
,
1
,
3
,
0
,
1
,
2
,
0
,
3
};
real_t
values
[]
=
{
1
,
3
,
2
,
-
1
,
-
4
,
-
1
,
1
,
1
,
3
};
CRSMatrix
mat
{
4
,
4
,
offset
,
indices
,
values
};
```
...
...
@@ -401,7 +457,7 @@ void mat_vec(real_t const alpha,
{
for
(
std
::
size_t
i
=
0
;
i
<
A
.
nrows
;
++
i
)
{
real_t
f
=
0.0
;
real_t
f
=
0.0
;
std
::
size_t
const
lb
=
A
.
offset
[
i
];
std
::
size_t
const
ub
=
A
.
offset
[
i
+
1
];
...
...
@@ -411,4 +467,121 @@ void mat_vec(real_t const alpha,
y
[
i
]
+=
alpha
*
f
;
}
}
```
\ No newline at end of file
```
---
# Advanced Datatypes
## Enumerations
A special datatype is available to define enumerations:
```
c++
enum
<
enum_name
>
{
<
name_1
>
,
<
name_2
>
,
<
name_3
>
,...
};
```
### Example:
```
c++
enum
Symmetry
{
unsymmetric
,
symmetric
,
hermitian
};
Symmetry
s
;
if
(
s
==
symmetric
)
{
...
}
```
Enumerations are handled as integer datatypes by C++. By default, the
members of an enumeration are numbered from
`0`
to
`n-1`
, e.g.,
`<name_1> = 0, <name_2> = 1`
, etc..
---
# Advanced Datatypes
## Enumerations
One can also define the value of the enumeration members
explicitly:
```
c++
enum
Symmetry
{
unsymmetric
=
4
,
symmetric
=
17
,
hermitian
=
42
};
```
Since enumerations are equivalent to integer types, they can also be
used in
`switch`
statements:
```
c++
switch
(
s
)
{
case
symmetric
:
...;
break
;
case
hermitian
:
...;
break
;
case
unsymmetric
:
default:
...;
}
```
---
# Advanced Datatypes
## Enumerations
Sometimes it is useful to specify the integer of enums explicitly
```
c++
enum
<
enum_name
>
:
<
type
>
{
<
name_1
>
,
<
name_2
>
,
<
name_3
>
,...
};
```
### Example:
```
c++
enum
Symmetry
:
unsigned
short
{
unsymmetric
,
symmetric
,
hermitian
};
```
---
# Advanced Datatypes
## Enumerations
By default, the enum values are introduced in the scope where the enum is defined. If there are
other variables/functions/... with the same name it could clash. It is thus recommended to introduce
a corresponding
*named scope*
for the enum values:
```
c++
enum
class
<
enum_name
>
[
:
<
type
>
]
{
<
name_1
>
,
<
name_2
>
,
...
}
```
### Example:
```
c++
enum
class
Symmetry
{
unsymmetric
,
symmetric
,
hermitian
};
Symmetry
s
;
switch
(
s
)
{
case
Symmetry
::
unsymmetric
:
...;
}
```
---
# Advanced Datatypes
## Enumerations
By default, the enum values are introduced in the scope where the enum is defined. If there are
other variables/functions/... with the same name it could clash. It is thus recommended to introduce
a corresponding
*named scope*
for the enum values:
```
c++
enum
class
<
enum_name
>
[
:
<
type
>
]
{
<
name_1
>
,
<
name_2
>
,
...
}
```
### Example:
```
c++
enum
class
Symmetry
{
unsymmetric
,
symmetric
,
hermitian
};
Symmetry
s
;
switch
(
s
)
{
using
enum
Symmetry
;
// [c++20]
case
unsymmetric
:
...;
}
```
presentation/_includes/arrays-and-dynamic-memory.md
View file @
f3fb9168
...
...
@@ -265,6 +265,22 @@ std::cout << p[4] << std::endl; // yields n[4]
The index operator
`[i]`
of a pointer
`p`
gives access to the
`i`
'th element of the array
starting at address
`p`
.
---
# Arrays and Dynamic Memory
## Pointer Arithmetic
Pointers can be "moved" in memory, i.e., they can point to the "next" or "previous" memory region.
Moving a pointer can be done by simple arithmetic operations with integers:
Let
`<type>* p`
be a pointer addressing data of type
`<type>`
and
`i`
and integer, then
-
`p + i`
,
`i + p`
points to the address
`<p> + i*sizeof(<type>)`
-
`p - i`
points to the address
`<p> - i*sizeof(<type>)`
-
`p++`
,
`++p`
is equivalent to
`p = p+1`
-
`p[i]`
is equivalent to
`*(p + i)`
---
# Arrays and Dynamic Memory
...
...
presentation/_includes/modules-and-namespaces.md
0 → 100644
View file @
f3fb9168
---
class
:
center, middle
# Modules and Namespaces
---
# Modules and Namespaces
## Header Files
Up to now, all source code was placed into one file. For
reasonable programs, this is not desirable, especially if functions are
reused by different programs.
Until C++20, we had no real module system in C++ like, e.g., Python or
Java, to group similar functions or types. Instead,
**header**
files are used to make C++ entities known to different source files.
As you remember, functions can be used if they were previously declared
or implemented. By separating declaration and implementation into header
and source file:
.pure-g[.pure-u-1-2[.padding-5[
```
c++
// header file: f.hh
void
f
(
int
n
,
double
f
);
```
]].pure-u-1-2[.padding-5[
```
c++
// source file: f.cc
void
f
(
int
const
n
,
double
f
)
{
...
}
```
]]]
the function can be reused by just
**including**
the header file.
---
# Modules and Namespaces
## Header Files
Including another file into the current source code is
performed by the
`#include`
directive:
```
c++
#include
"filename"
// or
#include
<filename>
```
The first version is usually used for files in the same project, whereas
the second version is for files from other projects, e.g., the c++ standard library
or an external library.
```
c++
#include
"f.hh"
// contains declaration of "f"
int
main
()
{
f
(
42
,
3.1415926
);
}
```
---
# Modules and Namespaces
## Header Files
In order to compile a source file that includes another header file, we have to tell the compiler
where to find these files:
1.
With
`#include <filename>`
the compiler searches in all default system locations, internal compiler
locations, and all explicitly specified locations, see below.
2.
With
`#include "filename"`
the compiler searches additionally in the same directory as the source
file that includes
`filename`
.
3.
Search directories can be explicitly specified by the compiler option
`-I<dir>`
---
# Modules and Namespaces
## Header Files
### Example
-
The source file
`mat_vec.cc`
from the introductory example contains the line
`#include <boost/numeric/mtl/mtl.hpp>`
-
Thus, the compiler needs to know the directory
`<dir>`
that contains
<br>
`<dir>/boost/numeric/mtl/mtl.hpp`
-
The corresponding library that provides this file is
[
MTL4
](
https://www.simunova.com/de/mtl4/
)
-
Download the source by using
[
subversion
](
https://subversion.apache.org/
)
into the directory
`<libs>`
```
bash
cd
<libs>
svn checkout https://svn.simunova.com/svn/mtl4/trunk mtl4
```
-
Compile the source file by
```
bash
c++
-I
<libs>/mtl4 mat_vec.cc
-o
mat_vec
```
---
# Modules and Namespaces
## Header Files
By convention, the filename suffix of the header file should be either
`.h`
(like in C),
`.hh`
,
`.hpp`
, or
`.hxx`
.
The filename suffix for source files is, correspondingly
`.cc`
,
`.cpp`
, or
`.cxx`
.
> .h3[Note:] C++ standard libraries are provided in header files without suffix. The functions
> imported from *C* are in files with the `c` prefix: `#include <cmath>` vs. `#include <math.h>`.
---
# Modules and Namespaces
## C++ Library
The C++ compiler comes with a set of standard include
files containing declarations of many functions:
[
`<cstdlib>`
](
https://en.cppreference.com/w/cpp/header/cstdlib
)
: standard C functions, e.g.,
.font-md[
-
`std::exit`
: stop program,
-
`std::atoi`
and
`std::atof`
: string to
`int`
and
`double`
conversion,
-
`std::qsort`
: sort arrays,
-
`std::malloc`
and
`std::free`
: C-style dynamic memory management,
]
[
`<cmath>`
](
https://en.cppreference.com/w/cpp/header/cmath
)
: mathematical functions, e.g.,
.font-md[
-
`std::sqrt`
: square root,
-
`std::abs`
: absolute value,
-
`std::sin`
and
`std::cos`
,
-
`std::log`
: natural logarithm
]
---
# Modules and Namespaces
## C++ Library
[
`<cstdio>`
](
https://en.cppreference.com/w/cpp/header/cstdio
)
: C-style IO functions, e.g.,
.font-md[
-
`std::printf`
: print variables to standard output,
-
`std::fopen`
,
`std::fclose`
,
`std::fread`
and
`std::fwrite`
: file IO
]
[
`<cstring>`
](
https://en.cppreference.com/w/cpp/header/cstring
)
: string functions, e.g.,
.font-md[
-
`std::strlen`
: string length,
-
`std::strcat`
: string concatenation,
-
`std::strcmp`
: string comparison,
-
`std::strcpy`
: string copy
]
[
`<cctype>`
](
https://en.cppreference.com/w/cpp/header/cctype
)
: character tests, e.g.,
.font-md[
-
`std::isdigit`
: test for digit,
-
`std::islower`
: test for lower case,
-
`std::isspace`
: test for white-space
]
etc.
:
[
`<cassert>`
](
https://en.cppreference.com/w/cpp/header/cassert
)
,
[
`<cerrno>`
](
https://en.cppreference.com/w/cpp/header/cerrno
)
,
[
`<cinttypes>`
](
https://en.cppreference.com/w/cpp/header/cinttypes
)
,
[
`<climits>`
](
https://en.cppreference.com/w/cpp/header/climits
)
,
[
`<ctime>`
](
https://en.cppreference.com/w/cpp/header/ctime
)
.
---
# Modules and Namespaces
## C++ Library
Specific C++ functionality usually comes in the form of
the "
*standard template library*
". It is implemented via
`class`
es
(see later) and provided by the following header files:
`<iostream>`
: file input/output functions and classes,
`<vector>`
: dynamic containers similar to arrays,
`<valarray>`
: similar to
`vector`
but better suited for numerics,
`<limits>`
: functions for determining type limits, e.g. minimal or maximal
values,
`<map>`
: associative array, e.g. indices are arbitrary types,
`<list>`
: provides standard list and iterators,
`<complex>`
: provides complex datatype,
etc.
: The specific classes and their usage will be discussed later.
---
# Modules and Namespaces
## Libraries without Headers
BLAS or LAPACK are written in Fortran and no header files exist for C++. Therefore, we will have to
write them ourselves. Consider
```
fortran
SUBROUTINE
DGESVD
(
JOBU
,
JOBVT
,
M
,
N
,
A
,
LDA
,
S
,
U
,
LDU
,
VT
,
LDVT
,
$
WORK
,
LWORK
,
INFO
)
CHARACTER
JOBU
,
JOBVT
INTEGER
INFO
,
LDA
,
LDU
,
LDVT
,
LWORK
,
M
,
N
DOUBLE PRECISION
A
(
LDA
,
*
),
S
(
*
),
U
(
LDU
,
*
),
$
VT
(
LDVT
,
*
),
WORK
(
*
)
```
To define a C++ function corresponding to the above Fortran function
the datatypes have to be mapped to C++ types. In Fortran, every
variable is provided as a
**pointer**
, hence:
<table>
<tr><td><code
class=
"remark-inline-code"
>
CHARACTER
</td><td>
\(\t
o
\)
<code
class=
"remark-inline-code"
>
char
*
</code></td></tr>
<tr><td><code
class=
"remark-inline-code"
>
INTEGER
</td><td>
\(\t
o
\)
<code
class=
"remark-inline-code"
>
int
*
</code></td></tr>