Mentions légales du service

Skip to content
Snippets Groups Projects
Commit d1e0e20a authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Remove a superfluous line in some TP notebooks.

parent c881d845
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Object programming](/notebooks/2-ObjectProgramming/0-main.ipynb) - [TP 1](/notebooks/2-ObjectProgramming/1b-TP.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Introduction" data-toc-modified-id="Introduction-1">Introduction</a></span></li><li><span><a href="#EXERCICE-13:-introduce-PowerOfTwoApprox-structure" data-toc-modified-id="EXERCICE-13:-introduce-PowerOfTwoApprox-structure-2">EXERCICE 13: introduce <code>PowerOfTwoApprox</code> structure</a></span></li></ul></div>
%% Cell type:markdown id: tags:
### Introduction
[This notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.
We will start from the solution to exercice 10 of the procedural programming TP. (we let aside pointer functions and writing into an output file done in exercices 11 and 12). `initial_file.cpp` in the TP directory is a copy to the solution of this exercice (symbolic link wouldn't have worked with Docker).
`initial_file.cpp` is the solution to the exercice 10 (we drop the writing into an external file and the function pointers).
### EXERCICE 13: introduce `PowerOfTwoApprox` structure
We will tackle the same problem with a dedicated `struct` called `PowerOfTwoApprox` which will be used to represent a real by two integers: the numerator and the exponent to the power of 2 used in the denominator.
Create this structure and use it throughout the program (`compute_power_of_2_approx()` signature should for instance be modified accordingly).
The expected output is unchanged from the initial file:
````
[With 2 bits]: 0.65 ~ 3 / 2^2 (0.75) [error = 15/100]
[With 4 bits]: 0.65 ~ 10 / 2^4 (0.625) [error = 4/100]
[With 6 bits]: 0.65 ~ 42 / 2^6 (0.65625) [error = 1/100]
[With 8 bits]: 0.65 ~ 166 / 2^8 (0.648438) [error = 0/100]
[With 2 bits]: 0.35 ~ 3 / 2^3 (0.375) [error = 7/100]
[With 4 bits]: 0.35 ~ 11 / 2^5 (0.34375) [error = 2/100]
[With 6 bits]: 0.35 ~ 45 / 2^7 (0.351562) [error = 0/100]
[With 8 bits]: 0.35 ~ 179 / 2^9 (0.349609) [error = 0/100]
[With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965 [error = 254/1000]
[With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448 [error = 119/1000]
[With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008 [error = 8/1000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 30/1000]
[With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967 [error = 2/1000]
[With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004 [error = 7/1000]
[With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977 [error = 0/1000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2/1000]
````
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_
_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Operators](/notebooks/3-Operators/0-main.ipynb) - [TP 8](/notebooks/3-Operators/1b-TP.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Introduction" data-toc-modified-id="Introduction-1">Introduction</a></span></li><li><span><a href="#EXERCICE-31:-replace-PowerOfTwoApprox::DoubleValue-by-an-operator-double" data-toc-modified-id="EXERCICE-31:-replace-PowerOfTwoApprox::DoubleValue-by-an-operator-double-2">EXERCICE 31: replace <code>PowerOfTwoApprox::DoubleValue</code> by an <code>operator double</code></a></span></li><li><span><a href="#EXERCICE-32:-replace-PowerOfTwoApprox::Multiply-by-operator-*" data-toc-modified-id="EXERCICE-32:-replace-PowerOfTwoApprox::Multiply-by-operator-*-3">EXERCICE 32: replace <code>PowerOfTwoApprox::Multiply</code> by <code>operator *</code></a></span></li><li><span><a href="#EXERCICE-33:-commutativity" data-toc-modified-id="EXERCICE-33:-commutativity-4">EXERCICE 33: commutativity</a></span></li><li><span><a href="#EXERCICE-34:-operator[]" data-toc-modified-id="EXERCICE-34:-operator[]-5">EXERCICE 34: <code>operator[]</code></a></span></li></ul></div>
%% Cell type:markdown id: tags:
### Introduction
[This notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.
We will start from the solution to exercice 30 of the procedural object TP. `initial_file.cpp` in the TP directory is a copy to the solution of this exercice (symbolic link wouldn't have worked with Docker).
%% Cell type:markdown id: tags:
### EXERCICE 31: replace `PowerOfTwoApprox::DoubleValue` by an `operator double`
The arguments should remain the same.
%% Cell type:markdown id: tags:
### EXERCICE 32: replace `PowerOfTwoApprox::Multiply` by `operator *`
Arguments remain unchanged.
%% Cell type:markdown id: tags:
### EXERCICE 33: commutativity
In `TestDisplaySum::Display()`, you should have the line
````
int approx = approx1 * coefficient1 + approx2 * coefficient2;
````
Try the following one instead:
````
int approx = coefficient1 * approx1 + coefficient2 * approx2;
````
You should get at least a warning doing so... (at least with the CMake build I provide that activates `-Wconversion` warning - more on that [later](/notebooks/6-InRealEnvironment/3-Compilers.ipynb)...)
Add a print line in `operator*`.
Do you understand what happens?
[Solution](/notebooks/3-Operators/1c-SolutionExercice33.ipynb)
%% Cell type:markdown id: tags:
### EXERCICE 34: `operator[]`
In `TestDisplayContainer`, replace `GetElement()` method by `operator[]`.
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_
_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Templates](/notebooks/4-Templates/0-main.ipynb) - [TP 11](/notebooks/4-Templates/1b-TP.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Introduction" data-toc-modified-id="Introduction-1">Introduction</a></span></li><li><span><a href="#EXERCICE-37:-make-PowerOfTwoApprox-a-template-class" data-toc-modified-id="EXERCICE-37:-make-PowerOfTwoApprox-a-template-class-2">EXERCICE 37: make <code>PowerOfTwoApprox</code> a template class</a></span></li><li><span><a href="#EXERCICE-38:-consistency" data-toc-modified-id="EXERCICE-38:-consistency-3">EXERCICE 38: consistency</a></span></li><li><span><a href="#EXERCICE-39:-crude-error-handling-for-the-overflow-issue" data-toc-modified-id="EXERCICE-39:-crude-error-handling-for-the-overflow-issue-4">EXERCICE 39: crude error handling for the overflow issue</a></span></li><li><span><a href="#EXERCICE-40:-more-template-functions" data-toc-modified-id="EXERCICE-40:-more-template-functions-5">EXERCICE 40: more template functions</a></span></li><li><span><a href="#EXERCICE-41:-another-error-handling..." data-toc-modified-id="EXERCICE-41:-another-error-handling...-6">EXERCICE 41: another error handling...</a></span></li></ul></div>
%% Cell type:markdown id: tags:
### Introduction
[This notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.
We will start from the solution to exercice 36 of the procedural object TP. `initial_file.cpp` in the TP directory is a copy to the solution of this exercice (symbolic link wouldn't have worked with Docker).
%% Cell type:markdown id: tags:
### EXERCICE 37: make `PowerOfTwoApprox` a template class
The integer type used for the numerator_ attribute of the `PowerOfTwoApprox` class was chosen arbitrarily. Make it a class template parameter.
Only the numerator will be modified: the denominator and the number of bits remain `int`.
Make sure to modify:
* The type of the data attribute.
* The type returned by the `Numerator()` method.
In the `TestDisplay` classes, we will for the moment keep instantiating the version with `int`.
**IMPORTANT:** For the friendship declaration in `PowerOfTwoApprox` to `operator*`, you need to specify another template for the function: you can't use the same as the class one:
````
template<class T>
class Foo
{
friend void MyFunction<Foo<T>>; // doesn't do what you really want!
};
````
````
template<class T>
class Foo
{
template<class U>
friend void MyFunction<Foo<U>>; // Ok!
};
````
%% Cell type:markdown id: tags:
### EXERCICE 38: consistency
So far, we aren't very self-consistent: we loosen the constraint on the type used to store the numerator, but it is used up against `int` elsewhere.
To highlight this, change `PowerOfTwoApprox` instantiation by replacing `int` by `short`: you should see warnings pop up...
To do so properly, you will have to make some classes and functions template. As you will see, doing such a change is rather cumbersome: it is better whenever possible to identify as soon as possible whether a template parameter is required or not.
We will do so step by step, each exercice dealing with part of the changes.
In the first step, we will:
* Modify `operator*` signature so that the return type and the argument use the template parameter rather than `int`.
* Make `TestDisplaySum` a template class as well: as it uses up directly `operator*`, you have to do it now.
You should see warnings to solve... and disturbing runtime effects: the computation gets stuck (we were not very aware so far of overflow issues and we end up here with infinite or at least very long loops...)
Don't get me wrong: the issue is not the templates themselves, but the fact our code is not robust enough and that we didn't see it previously as we worked on types and values (no more than 16 bits...) for which the potentiel problems were not appearant.
%% Cell type:markdown id: tags:
### EXERCICE 39: crude error handling for the overflow issue
This exercice is not template-related, but as often in software programming, we have obviously to deal swiftly with the unforeseen issue at hand so that we can keep working on what we intended to implement in the first place.
We will provide several fixes: we want to be able to track down when overflow occurs, and be able to print with `PrintNumericalError()` method that an overflow happens rather than a garbage value.
To do so, a boolean argument should be added to:
- `PowerOfTwoApprox` constructor [input/output]
- `TestDisplay::PrintNumericalError()` method [input]
- `times_power_of_2()` function [input/output]
- `max_int()` function [input/output]
that is set to true if an overflow occurred.
The two overflows to track down are:
- In `PowerOfTwoApprox` constructor:
If in the loop the numerator or the denominator is less than the one computed at the previous iteration, an overflow occurred. Implement a test and when this happens, exit the loop, print a message about the issue and set arbitrarily numerator and exponent to 0
- In `times_power_of_2`:
Before multiplying by 2., check number is less than half the maximum possible value for the type (use `std::numeric_limits<>::max()`).
We'll see [later](/notebooks/5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb) how to deal more cleanly with error handlings.
The output should look something like:
````
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 2404/1000000]
[With 12 bits]: 0.65 ~ 0.649902 (2662/2^12) [error = 150/1000000]
[With 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 9/1000000]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 17857/1000000]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 1116/1000000]
[With 12 bits]: 0.35 ~ 0.349976 (2867/2^13) [error = 70/1000000]
[With 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 29930/1000000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2012/1000000]
[With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 252/1000000]
Overflow happened in PowerOfTwoApprox constructor for value 0.65 over 16 bits; everything is therefore set arbitrarily to zero at the moment.
Overflow happened in PowerOfTwoApprox constructor for value 0.35 over 16 bits; everything is therefore set arbitrarily to zero at the moment.
[With 16 bits]: Overflow!
````
%% Cell type:markdown id: tags:
### EXERCICE 40: more template functions
We will first heed the warnings: there is a type inconsistency due to the fact this function expects `int` and is fed `short`. Make some functions template ones to fix some of the warnings: `times_power_of_2`, `max_int` and `round_as_int`.
**WARNING:** You may have a hard time fixing the one concerning `operator*` due to a pesky
````
warning: implicit conversion loses
integer precision: 'int' to 'short' [-Wconversion]
return times_power_of_2(approx.Numerator() * coefficient, -approx.Exponent());
````
This is due to a specificity I was not aware of before preparing this very TP: an arithmetic operator involving two `short` actually returns an `int`! For more of this, see this [StackOverflow question](https://stackoverflow.com/questions/24371868/why-must-a-short-be-converted-to-an-int-before-arithmetic-operations-in-c-and-c). I actually wasn't aware of this because I never use `short`: I was told long ago it was often a pessimization compared to a mere `int` and didn't dig deeper than that; the issue we met here seems to confirm it is quirky to use.
One can fix the warning with an additional `static_cast`:
%% Cell type:code id: tags:
``` C++17
// Doesn't run in Xeus-cling
template<class IntT>
IntT operator*(const PowerOfTwoApprox<IntT>& approx, IntT coefficient)
{
// static_cast to deal with the `short` case
return static_cast<IntT>(times_power_of_2(approx.Numerator() * coefficient, -approx.Exponent()));
}
```
%% Output
input_line_7:2:22: error: no template named 'PowerOfTwoApprox'
IntT operator*(const PowerOfTwoApprox<IntT>& approx, IntT coefficient)
 ^

Interpreter Error:
%% Cell type:markdown id: tags:
### EXERCICE 41: another error handling...
_Optional: you may want to take the solution directly!_
Previous exercice should also underline another limitation: we may detect the errors in building a `PowerOfTwoApprox`, but all bets are off when we perform arithmetics... Once again templates aren't the cause of our issue, it's just that the problem was hidden with the `int` used beforehand.
The issue we have now is that in plain arithmetic operations between `short`, we may overflow, especially considering our test example in which coefficients are already in the thousands.
This [StackOverflow post](https://stackoverflow.com/questions/199333/how-to-detect-unsigned-integer-multiply-overflow) provides an interesting non-standard feature introduced in clang and gcc to deal with this: special functions that tell if an operation will overflow (other replies give hints to do so manually).
The functions to use are:
````
__builtin_add_overflow(T a, T b, T& sum)
__builtin_mul_overflow(T a, T b, T& product)
````
where T is the type considered; these functions return 0 if no overflow occurs (and result is in this case given in third argument).
Use them in `TestDisplaySum<IntT>::Display()` and `operator*(const PowerOfTwoApprox<IntT>& approx, IntT coefficient)` to control the arithmetic operations there.
Expected result is:
````
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 2404/1000000]
[With 12 bits]: 0.65 ~ 0.649902 (2662/2^12) [error = 150/1000000]
[With 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 9/1000000]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 17857/1000000]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 1116/1000000]
[With 12 bits]: 0.35 ~ 0.349976 (2867/2^13) [error = 70/1000000]
[With 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]
Overflow in operator*(PowerOfTwoApprox, integer)! Arbitrary max value will therefore be returned.
Overflow in operator*(PowerOfTwoApprox, integer)! Arbitrary max value will therefore be returned.
Overflow in estDisplaySum<IntT>::Display in sum.
[With 4 bits]: Overflow!
Overflow in operator*(PowerOfTwoApprox, integer)! Arbitrary max value will therefore be returned.
Overflow in operator*(PowerOfTwoApprox, integer)! Arbitrary max value will therefore be returned.
Overflow in estDisplaySum<IntT>::Display in sum.
[With 8 bits]: Overflow!
Overflow in operator*(PowerOfTwoApprox, integer)! Arbitrary max value will therefore be returned.
Overflow in operator*(PowerOfTwoApprox, integer)! Arbitrary max value will therefore be returned.
Overflow in estDisplaySum<IntT>::Display in sum.
[With 12 bits]: Overflow!
Overflow in times_power_of_2!
Overflow happened in PowerOfTwoApprox constructor for value 0.65 over 16 bits; everything is therefore set arbitrarily to zero at the moment.
Overflow in times_power_of_2!
Overflow happened in PowerOfTwoApprox constructor for value 0.35 over 16 bits; everything is therefore set arbitrarily to zero at the moment.
[With 16 bits]: Overflow!
````
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_
_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [How to do the TP](/notebooks/TP/HowTo.ipynb)
%% Cell type:markdown id: tags:
## Introduction
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#How-to-do-the-exercices?" data-toc-modified-id="How-to-do-the-exercices?-1">How to do the exercices?</a></span><ul class="toc-item"><li><span><a href="#Don't-do-the-TP-in-Jupyter-notebook!" data-toc-modified-id="Don't-do-the-TP-in-Jupyter-notebook!-1.1">Don't do the TP in Jupyter notebook!</a></span></li><li><span><a href="#Online-compilers" data-toc-modified-id="Online-compilers-1.2">Online compilers</a></span></li><li><span><a href="#On-your-local-machine" data-toc-modified-id="On-your-local-machine-1.3">On your local machine</a></span><ul class="toc-item"><li><span><a href="#How-to-compile-and-run-the-program?" data-toc-modified-id="How-to-compile-and-run-the-program?-1.3.1">How to compile and run the program?</a></span></li><li><span><a href="#For-each-exercice" data-toc-modified-id="For-each-exercice-1.3.2">For each exercice</a></span></li></ul></li><li><span><a href="#With-Docker" data-toc-modified-id="With-Docker-1.4">With Docker</a></span></li></ul></li></ul></div>
%% Cell type:markdown id: tags:
## How to do the exercices?
TPs are interspeded throughout the lecture, and are really recommended as it is a way to check you truly assimilated what was explained in the notebooks (in programming rather often things seem easy... until you try to do them by yourself!)
There are basically three ways to do the exercices, but I will start with the one to avoid:
### Don't do the TP in Jupyter notebook!
Jupyter notebooks are a great tool to provide a decent and interactive support for lectures, and we can really thank the [guys behind Xeus-cling](https://github.com/QuantStack/xeus-cling/graphs/contributors) for their amazing work to port C++ into an interpreter-like environment.
However, it is clearly not an environment for direct development: the fact you need to restart the kernel and rerun all relevant cells each time you modify a function is extremely cumbersome during the trial-and-error that is often the implementation of code.
### Online compilers
[Coliru](https://coliru.stacked-crooked.com/) or [Wandbox](https://wandbox.org/) provides online compilers in which you may paste code, compile it and then run it.
They are clearly the easiest way to go that we recommend heavily! (except for the [TP related to file structure](/notebooks/6-InRealEnvironment/2-b-TP.ipynb) for which we will need to work locally).
They are clearly the easiest way to go (except for the [TP related to file structure](/notebooks/6-InRealEnvironment/2-b-TP.ipynb) for which we will need to work locally).
### On your local machine
This implies a _recent_ compiler is already installed on your machine and ready to use.
I provide in the folder in which TPs are set a very basic and crude `CMakeLists.txt` that should provide compilation (at least on Unix systems).
#### How to compile and run the program?
First create a folder in which the executables will be built and initialize CMake here:
````
mkdir -p build
cd build
cmake ..
````
Now in this folder you may run `make` to build the executables.
At first only `initial_file.cpp` is compiled into a `initial` executable.
You may run it through:
`./initial`
and if everything is allright you should see (in the case of the first TP 1-ProceduralProgramming):
````
0.65 ~ 1 / 2^1
0.65 ~ 3 / 2^2
0.65 ~ 5 / 2^3
````
Each time a change is made or a new file is added in `CMakeLists.txt`, you just need to run again `make` command.
#### For each exercice
The idea is to start from `initial_file.cpp` and modify it slightly in each exercice.
You need therefore to copy this file and create a new executable; you have basically two options:
* Using one file for all exercices in a given thematic. The pro is that you won't need to edit the CMakeLists.txt more than once, the con is that you don't keep the intermediate states of your work.
* Use a file per exercice; when beginning a new one you need to:
* Copy the former one into new cpp file, e.g. `cp exercice1.cpp exercice2.cpp`.
* Edit the CMakeLists.txt and uncomment the relevant line, e.g. `add_executable(exercice2 exercice2.cpp)`
I have done the latter but feel free to do the former if you wish.
### With Docker
I also provide a [Docker](https://www.docker.com/) image in which a very basic Fedora environment is displayed.
You may compile / run the code in a Docker container and edit your file in your computer environment with you favored editor / IDE.
The steps to compile are the same as presented in the previous section.
For more informations about the Docker way please look the dedicated [README](https://gitlab.inria.fr/formations/cpp/gettingstartedwithmoderncpp/blob/master/TP/README.md) (the one within the TP folder of the root directory).
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_
_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment