Commit 4cacfbbc authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Remove exercises from index

parent f14eeae2
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <cstdlib>
using T = double;
static const int N = 100;
/// Calculate sum_{k=0}^N x[k] using Kahan summation algorithm
T kahan(std::vector<T> const& x)
{
// your implementation here
return sum;
}
/// Calculate sum_{k=0}^N x[k] using standard summation
T simple(std::vector<T> const& x)
{
// your implementation here
return sum;
}
int main()
{
std::vector<T> x(N);
// fill the vector using element access x[i]
}
#include <cmath>
// Return the square-root of a calculated recursively with break condition x0 and recursion depth N
/**
* Recursion defined by
* x_n := x_{n-1} - f(x_{n-1})/f'(x_{n-1})
* with x_0 = x0
* for f(x) = x*x - a and f'(x) = df(x)/dx
*
* Return the value x_N.
**/
double sqrt_recu(double a, double x0, int N)
{
// your implementation here
}
// Return the square-root of a calculated iteratively, starting from initial value x0 with N iterations
/**
* Iteration defined by
* x_{n+1} := x_{n} - f(x_{n})/f'(x_{n})
* with x_0 = x0
* for f(x) = x*x - a and f'(x) = df(x)/dx
*
* Return the value x_N.
**/
double sqrt_iter(double a, double x0, int N)
{
// your implementation here
}
int main()
{
// test for a=10, x0=3, and N={5,10,100}
// compare against std::sqrt
}
\ No newline at end of file
int bicgstab_ell(const LinearOperator &A, Vector &x, const Vector &b,
const LeftPreconditioner &L, RightPreconditioner const& R,
Iteration& iter, size_t l)
{
using mtl::size; using mtl::irange; using mtl::imax; using mtl::mat::strict_upper;
typedef typename mtl::Collection<Vector>::value_type Scalar;
typedef typename mtl::Collection<Vector>::size_type Size;
if (size(b) == 0) throw mtl::logic_error("empty rhs vector");
const Scalar zero= math::zero(Scalar()), one= math::one(Scalar());
Vector x0(resource(x)), y(resource(x));
mtl::dense_vector<Vector> r_hat(l+1,Vector(resource(x))), u_hat(l+1,Vector(resource(x)));
// shift problem
x0= zero;
r_hat[0]= b;
if(two_norm(x)!=zero){r_hat[0]-= A * x;x0= x;x= zero;}
Vector r0_tilde(r_hat[0]/two_norm(r_hat[0]));
y= solve(L, r_hat[0]);
r_hat[0]= y;
u_hat[0]= zero;
Scalar rho_0(one), rho_1(zero), alpha(zero), Gamma(zero), beta(zero), omega(one);
mtl::mat::dense2D<Scalar> tau(l+1, l+1);
mtl::dense_vector<Scalar> sigma(l+1), gamma(l+1),
gamma_a(l+1), gamma_aa(l+1);
while (! iter.finished(r_hat[0])) {
++iter;
rho_0= -omega * rho_0;
for (Size j= 0; j < l; ++j) {
rho_1= dot(r0_tilde, r_hat[j]);
beta= alpha * rho_1/rho_0; rho_0= rho_1;
for(Size i= 0; i <= j; ++i) u_hat[i]= r_hat[i] - beta * u_hat[i];
y= A * Vector(solve(R, u_hat[j]));
u_hat[j+1]= solve(L, y);
Gamma= dot(r0_tilde, u_hat[j+1]);alpha= rho_0 / Gamma;
for (Size i= 0; i <= j; ++i)
r_hat[i]-= alpha * u_hat[i+1];
if (iter.finished(r_hat[j]))
{x= solve(R, x);x+= x0;return iter;}
r_hat[j+1]= solve(R, r_hat[j]);
y= A * r_hat[j+1];
r_hat[j+1]= solve(L, y);
x+= alpha * u_hat[0];
}
// mod GS (MR part)
irange i1m(1, imax);
mtl::dense_vector<Vector> r_hat_tail(r_hat[i1m]);
tau[i1m][i1m]= orthogonalize_factors(r_hat_tail);
for (Size j= 1; j <= l; ++j)
gamma_a[j]= dot(r_hat[j], r_hat[0]) / tau[j][j];
gamma[l]= gamma_a[l]; omega= gamma[l];
if (omega == zero) return iter.fail(3, "bicg breakdown #2");
// is this something like a tri-solve?
for (Size j= l-1; j > 0; --j) {
Scalar sum= zero;
for (Size i=j+1;i<=l;++i)
sum += tau[j][i] * gamma[i];
gamma[j] = gamma_a[j] - sum;}
gamma_aa[irange(1, l)]= strict_upper(tau[irange(1,l)][irange(1,l)])*gamma[irange(2,l+1)]+gamma[irange(2,l+1)];
x+= gamma[1] * r_hat[0];
r_hat[0]-= gamma_a[l]*r_hat[l];
u_hat[0]-= gamma[l]*u_hat[l];
for(Size j=1;j<l;++j){u_hat[0]-=gamma[j]*u_hat[j];
x+= gamma_aa[j] * r_hat[j];
r_hat[0] -= gamma_a[j] * r_hat[j];
}}
x= solve(R, x); x+= x0; // convert to real solution and undo shift
return iter;}
\ No newline at end of file
#include <iostream>
#include <typeinfo>
// function template returning the identity element of type T
template <class T>
T identity();
// function template returning a random element of type T
template <class T>
T random();
// a + b can be assigned to a type T
template <class T>
bool test_closure(T const& a, T const& b)
{
T c{ a + b }; // construction from a + b
c = a + b; // assignment to T
return true;
}
// for all a,b,c the associativity law holds
template <class T>
bool test_associativity(T const& a, T const& b, T const& c)
{
return (a + b) + c == a + (b + c);
}
// the order of the operands can be interchanged
template <class T>
bool test_commutativity(T const& a, T const& b)
{
return a + b == b + a;
}
// there exists an identity element
template <class T>
bool test_identity(T const& a)
{
T e{ identity<T>() };
return (e + a == a) && (a + e == a);
}
// for all elements a there exists an inverse element -a
template <class T>
bool test_inverse(T const& a)
{
T inv_a{ -a };
T e{ identity<T>() };
return (a + inv_a == e) && (inv_a + a == e);
}
template <class T>
bool test()
{
bool has_closure = true;
bool has_associativity = true;
bool has_commutativity = true;
bool has_identity = true;
bool has_inverse = true;
// run a test with random data 100 times
for (int i = 0; i < 100; ++i) {
T a{ random<T>() };
T b{ random<T>() };
T c{ random<T>() };
has_closure = has_closure && test_closure(a,b);
has_associativity = has_associativity && test_associativity(a,b,c);
has_commutativity = has_commutativity && test_commutativity(a,b);
has_identity = has_identity && test_identity(a);
has_inverse = has_inverse && test_inverse(a);
}
std::cout << "The type T=" << typeid(T).name() << " has the following properties:" << std::endl;
std::cout << " closure: " << has_closure << std::endl;
std::cout << " associativity: " << has_associativity << std::endl;
std::cout << " commutativity: " << has_commutativity << std::endl;
std::cout << " identity: " << has_identity << std::endl;
std::cout << " inverse: " << has_inverse << std::endl;
return has_associativity && has_closure && has_inverse && has_identity && has_commutativity;
}
......@@ -86,8 +86,8 @@ and "Todos" tabs, and the "Wiki" tab. If and how you use these features is up to
- [Git reference](https://www.git-scm.com/docs)
- [cheat sheet](https://github.github.com/training-kit/downloads/github-git-cheat-sheet.pdf)
## Exercise 2 (Compiling code)
## Exercise 2 (Compiling code)
In the directory [material/sheet1/](/exercises/material/sheet1) you can find
an initial C++ example in the files `linear_algebra.cc`, `linear_algebra.h`, and `exercise2.cc`. Download the files and compile the code:
......
# Exercise sheet 2
## Exercise 1 (Floating-point numbers)
1. What is the difference between `float` and `double`?
2. Assume the following program needs 1 second to run:
```c++
int main()
{
double x = 1.0e8;
while (x > 0)
{
--x;
}
}
```
How long would it run if you replace `double` by `float`? Why?
3. Look at the following code example:
```c++
#include <cassert>
int main()
{
using T = float; // a type-alias
T a = 0.15 + 0.15;
T b = 0.1 + 0.2;
assert(a == b);
assert(a >= b);
}
```
where `assert` is a macro resulting in an error if the argument evaluates to `false`. What is the effect of the
program? What happens if we change `float` to `double`? Why?
### Resources
- https://en.wikipedia.org/wiki/Floating-point_arithmetic
- https://en.wikipedia.org/wiki/IEEE_754
## Exercise 3 (Control structures)
Get familiar with control structures in C++, i.e. `if`, `else`, `for`, `do`, `while`, `switch`, `case`.
1. Rewrite the following `while`-loop by a `for`-loop:
```c++
int log10 = 0;
double num = 12345.0;
while (num >= 10.0) {
num /= 10.0;
++log10;
}
```
2. What is the error in the following statements?
i.
```c++
for (int j = 0, j < 10, ++j)
std::cout << j;
```
ii.
```c++
int n, sum = 0;
do
{ std::cin >> n; sum += n; }
while (n > 0)
```
iii.
```c++
int n = 2, m;
while (n < 10)
m *= n, ++n;
```
iv.
```c++
unsigned long n = 0;
int cnt = 1;
do
n += cnt;
cnt++;
while (n < 100);
```
3. Write a C++-program that calculates and prints the sum of the first $`n`$ positive integers, i.e.
```math
1^2 + 2^2 + 3^2 + 4^2 + ... + n^2
```
while a positive integer is read from the keyboard. Use the standard stream operator `std::cin >> ...` and
`std::cout << ...` from `<iostream>` for reading and writing.
### Resources
- [if-then-else](https://en.cppreference.com/w/cpp/language/if), [switch-case](https://en.cppreference.com/w/cpp/language/switch),
[for-loop](https://en.cppreference.com/w/cpp/language/for), [while-loop](https://en.cppreference.com/w/cpp/language/while),
[do-while-loop](https://en.cppreference.com/w/cpp/language/do)
- [std::cout](https://en.cppreference.com/w/cpp/io/cout), [std::cin](https://en.cppreference.com/w/cpp/io/cin)
## Exercise 4 (Kahan Summation Formula)
Calculate the sum $`\sum_{j=0}^{N-1} x_j`$ for a given set of values $`\{x_j\}`$ using the following algorithm:
```
S = x_0
C = 0
for j = 1,..., N-1 do
Y = x_j - C
T = S + Y
C = (T - S) - Y
S = T
```
What is the difference to a classical summation algorithm?
1. Create a `std::vector` with 100 `float`/`double` values: $`x_k := \bar{x}^k/(k!)`$ with $`\bar{x} = 7`$.
2. Sum up these values using the Kahan-algorithm and a simple summation, with internal value format `float`/`double`.
3. Compare the result of the summation of `float`s to `double`s and compare to the function `std::exp` from `<cmath>`.
4. Compile your program with
- `g++ -std=c++11 SOURCE.cc`
- `g++ -std=c++11 -O3 -ffast-math SOURCE.cc`
- `clang++ -std=c++11 SOURCE.cc`
- `clang++ -std=c++11 -O3 -ffast-math SOURCE.cc`
What is the difference, if any? Why is there a difference in the output?
5. Try again, but reverse the order of the entries of the vector, i.e.
```c++
#include <algorithm>
...
std::reverse(x.begin(), x.end());
```
6. Try again, but first randomly shuffle the entries of the vector, i.e.
```c++
#include <algorithm>
#include <cstdlib>
...
std::srand(12345); // fixed initial seed
std::random_shuffle(x.begin(), x.end(), [](int n) { return std::rand() % n; });
```
### Note
For a comparison of the computations, print the value with maximal precision to `std::cout`, i.e.
```c++
#include <iomanip>
#include <iostream>
...
std::cout << std::setprecision(std::numeric_limits<T>::max_digits10) << SUM << std::endl;
```
where `T` is a placeholder for the type that is used, and `SUM` for the value calculated.
### Material
- [material/sheet2/exercise4.cc](/exercises/material/sheet2/exercise4.cc)
### Resources
- [Kahan Summation](https://en.wikipedia.org/wiki/Kahan_summation_algorithm)
- [std::vector](https://en.cppreference.com/w/cpp/container/vector),
[std::exp](http://en.cppreference.com/w/cpp/numeric/math/exp)
- [Optimization options](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html),
[fast-math](http://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do)
## Exercise 5 (GotW-86: Slight typos)
See [GotW #86](http://www.gotw.ca/gotw/086.htm). Answer the following question without using a compiler.
What is the output of the following program on a standards-conforming C++ compiler?
```c++
#include <iostream>
#include <iomanip>
int main()
{
int x = 1;
for( int i = 0; i < 100; ++i );
// What will the next line do? Increment???????????/
++x;
std::cout << x << std::endl;
}
```
\ No newline at end of file
# Exercise sheet 3
## Exercise 1 (Literals)
What is the type of the following literals
```c++
(a) 2L (d) 1.23456f (g) 0302
(b) '\101' (e) 100UL (h) .1e-5
(c) 0x10 (f) 1.2345678 (i) 0xFL
```
### Hints
To check the type, you can use `decltype` and `static_assert`:
```c++
#include <type_traits>
// ...
static_assert(std::is_same<decltype(LITERAL), TYPE>::value, "Wrong type");
```
(You have to compile this code with `-std=c++11` flag)
### Resources
- [cppreference:literals](https://en.cppreference.com/w/cpp/language/expressions#Literals)
## Exercise 2 (Variable declaration)
What is the error in the following variable definitions?
```c++
(a) int n, int i; (c) double side length; (e) Short min(0);
(b) int m; double result{.5} (d) char c['a']; (f) double slow_down = "1.E-4";
```
## Exercise 3 (Operators)
What is the meaning of the following arithmetic expressions? To illustrate which sub-expression is evaluated first, add brackets!
```c++
(a) x / y * z (g) z-y-x?x+y+z:x-y-z
(b) x * y++ / -z (h) z<<x>>y
(c) x^2 + y^2 (i) z>>x<<y
(d) ++x * x++ (j) x||y||z
(e) *&x*y&&z (k) ++x*=y++
(f) x+++x (l) -~x^x
```
What is the value of the expressions with the following value of the variables?
```c++
int x = 3;
int y = 2;
int z = 5;
```
What is the value of the variables `x`, `y`, and `z` after evaluating the expression?
First, try to evaluate by hand, then check your results by implementing the expressions.
### Resources
- [cppreference:expressions](https://en.cppreference.com/w/cpp/language/expressions#Operators),
[cppreference:operator_precedence](https://en.cppreference.com/w/cpp/language/operator_precedence)
- [Wikibook:Operatoren](https://de.wikibooks.org/wiki/C%2B%2B-Programmierung:_Operatoren)
## Exercise 4 (Recursion)
To calculate the square-root of a real number $`a > 0`$ you can use the Newton-method, by getting the root (zero-point) of the function $`f(x)`$,
defined by:
```math
f(x) := x^2 - a,
```
i.e., $`f(x) = 0 \Leftrightarrow |x|=\sqrt{a}`$.
The Newton-method introduces an iteration $`x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}`$ starting from some initial value $`x_0`$.
This calculation rule can be interpreted as a recursion in the sense:
```math
T: x\mapsto x - f(x)/f'(x),\quad
T(x_n) = T(T(x_{n-1})),\;
x_0 = \text{\texttt{x0}}
```
or it can be interpreted as in iteration starting from $`x_0`$ and iteratively calculating the next value.
Implement the functions
```c++
double sqrt_recu(double a, double x0, int N); // returns x_N
double sqrt_iter(double a, double x0, int N); // returns x_N
```
by realizing this code _recursively_ and _iteratively_. Use `x0` as recursion break condition or initial value $`x_0`$ and return the value `x_N`
as your approximation of the square-root of `a`.
Try your code with a recursion depth of $`N=5, 10, 100`$ for $`a=10`$ and initial value $`x_0=3`$.
How to check the error you have made? How to choose the initial value `x0` and the iteration count `N`? How would you design your implementation
`double sqrt(double a)` of a square-root function and which version of the implementation above would you choose?
### Notes and additional questions:
- You can use the `std::sqrt` function from `<cmath>` as a comparison.
- (optional) Measure the time of your implementation and compare it against the time of the `std::sqrt` implementation. Therefore, either use the `Timer`
in the lecture material folder, or user the Google micro benchmarking suite: https://github.com/google/benchmark
- (optional) What happens if your change your type from `double` to `float`. Do you see any difference in accuracy and performance?
### Material
- [material/sheet3/exercise4.cc](/exercises/material/sheet3/exercise4.cc)
### Resources
- [std::sin](https://en.cppreference.com/w/cpp/numeric/math/sin)
## Exercise 5 (GotW-78: Operators, Operators Everywhere)
See [GotW #78](http://www.gotw.ca/gotw/078.htm).
1. What is the greatest number of plus signs (`+`) that can appear consecutively, without whitespace, in a
valid C++-program?
*Note:* Of course, plus signs in comments, preprocessor directives and macros, and literals don't count.
That would be too easy.
2. **Guru Question**: Similarly, what is the greatest number of each the following characters that can appear
consecutively, without whitespace, outside comments in a valid C++-program?
- `&`,
- `<`,
- `|`.
For example, the code `if( a && b )` trivially demonstrates two consecutive `&` characters in a
valid C++-program.
# Exercise sheet 4
## Exercise 1 (Work with references and constants)
*References* are aliases to existing objects or functions. In contrast to pointers, references are
not just addresses, but refer to the data behind that addresses. They can be used like regular variables
and are declared with the symbol `&`:
```c++
TYPE & VARNAME = OBJECT;
```
So, the reference variable `VARNAME` now binds to the aliased object `OBJECT`. References must be initialized
directly and are always bound to one object.
A data-type with the qualifier `const` is called a *constant* and is immutable. It can be declared as
```c++
TYPE const VARNAME = VALUE;
```
Constants can not be modified and thus must be initialized directly.
1. Write a function `foo(...)` that gets one argument, either
- `double` value
- `double const` value
- `double` reference,
- `double const` reference,
Change the value of the referenced data inside the function. Is it always possible?
2. Define functions `f(char)`, `g(char&)`, and `h(char const&)`. Call them with the arguments `'a'`,
`49`, `3300`, `c`, `uc`, and `sc`, where `c` is a `char`, `uc` is an `unsigned char`, and `sc` is a `signed char` variable.
Which calls are legal? Which calls cause the compiler to introduce a *temporary variable*?
### Resources
- [cppreference:reference](https://en.cppreference.com/w/cpp/language/reference),
[cppreference:const](https://en.cppreference.com/w/cpp/language/cv)
- [Guidelines](https://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters)
- [const-correctness](https://isocpp.org/wiki/faq/const-correctness)
## Exercise 2 (Structs)
A `struct` in C++ is one type of class encapsulating data and methods that act on this data.
The most simple structs are those just containing data. In this sense a `struct` is a compound data-type.
Each data-type has a size in memory. This can be evaluated with `sizeof(TYPE)` or `sizeof(EXPRESSION)`.
The actual total size of the data-type might depend on its members and the order of its members.
1. Define a `struct` with a member of each of the types `bool`, `char`, `int`, `long`, `double`, and `long double`.
Order the members so as to get the largest size of the struct and the smallest size of the struct.
2. What is the size of an empty `struct` without any member variables? Why?
### Note
- While you might get different sizes of the struct type when reordering the members, this saving seems to be small, but
when you allocate a vector of that many of these types, you might end up with large memory savings.
- But be aware of the fact, that the order of members does not only affect the memory size, but also the
read and write performance when accessing the members. See the blog post of Jonas Devlieghere from below.
### Resources
- [cppreference:class](https://en.cppreference.com/w/cpp/language/class)
- https://jonasdevlieghere.com/order-your-members/
## Exercise 3 (Code formatting)
It is recommended to follow some code style guidelines. Be consistent with naming, indentation, brackets, etc. This is not
for the compiler. A program can read any valid source code. But it is for you now, for your coworkers or for you in the future when
you reopen some old code. Style your code consistently from the first line.
A minimal guideline is given in the README. But there is more. And there are different common styles. Sometimes you get code from someone
else and need to read/understand it. A good starting point is to transform the code to your code style. This can be automated.
In `material/sheet4/exercise3.cc` you can find a horribly complicated unreadable code. Reformat it, using some tools:
- [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
- [astyle](http://astyle.sourceforge.net/)
- [uncrustify](http://uncrustify.sourceforge.net/)
### Resources
- [Google code style](https://google.github.io/styleguide/cppguide.html),
- [Indentation styles](https://en.wikipedia.org/wiki/Indentation_style)
- [Cpp Core guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)
## Exercise 4 (Rational numbers)
Write a class for rational numbers. The number should always be represented as *fully reduced fraction* of the form
```math
\frac{\text{numerator}}{\text{denominator}}
```
with $`\text{denominator} > 0`$.
1. What is an appropriate data structure for rational numbers?
2. Start by writing a function `int gcd(int,int)` (greatest common devisor), you will need it to reduce fractions