Mentions légales du service

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

Fix broken link.

parent faab357a
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 1](/notebooks/1-ProceduralProgramming/4b-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><ul class="toc-item"><li><span><a href="#How-to-do-the-TP?" data-toc-modified-id="How-to-do-the-TP?-1.1">How to do the TP?</a></span></li><li><span><a href="#The-problem-we'll-deal-with-throughout-the-TPs" data-toc-modified-id="The-problem-we'll-deal-with-throughout-the-TPs-1.2">The problem we'll deal with throughout the TPs</a></span></li><li><span><a href="#EXERCICE-1:-Adding-a-loop" data-toc-modified-id="EXERCICE-1:-Adding-a-loop-1.3"><strong>EXERCICE 1: Adding a loop</strong></a></span></li><li><span><a href="#EXERCICE-2:-Adding-a-function" data-toc-modified-id="EXERCICE-2:-Adding-a-function-1.4"><strong>EXERCICE 2: Adding a function</strong></a></span></li><li><span><a href="#EXERCICE-3:-compute-the-approximation" data-toc-modified-id="EXERCICE-3:-compute-the-approximation-1.5"><strong>EXERCICE 3: compute the approximation</strong></a></span></li><li><span><a href="#EXERCICE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator." data-toc-modified-id="EXERCICE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator.-1.6"><strong>EXERCICE 4: Search for the best approximation for a given maximum numerator.</strong></a></span></li><li><span><a href="#EXERCICE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits" data-toc-modified-id="EXERCICE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits-1.7"><strong>EXERCICE 5: Computation of the maximum numerator as a function of the number of bits</strong></a></span></li><li><span><a href="#EXERCICE-6:-moving-display-to-a-new-intermediate-function" data-toc-modified-id="EXERCICE-6:-moving-display-to-a-new-intermediate-function-1.8"><strong>EXERCICE 6: moving display to a new intermediate function</strong></a></span></li><li><span><a href="#EXERCICE-7:-adding-error-in-display" data-toc-modified-id="EXERCICE-7:-adding-error-in-display-1.9"><strong>EXERCICE 7: adding error in display</strong></a></span></li><li><span><a href="#EXERCICE-8:-Multiplication" data-toc-modified-id="EXERCICE-8:-Multiplication-1.10"><strong>EXERCICE 8: Multiplication</strong></a></span></li><li><span><a href="#EXERCICE-9:-display-sum-of-two-multiply" data-toc-modified-id="EXERCICE-9:-display-sum-of-two-multiply-1.11">EXERCICE 9: display sum of two <code>multiply</code></a></span></li><li><span><a href="#EXERCICE-10:-print-error-in-display_sum()" data-toc-modified-id="EXERCICE-10:-print-error-in-display_sum()-1.12"><strong>EXERCICE 10: print error in <code>display_sum()</code></strong></a></span></li><li><span><a href="#EXERCICE-11:-function-pointers" data-toc-modified-id="EXERCICE-11:-function-pointers-1.13">EXERCICE 11: function pointers</a></span></li></ul></li></ul></div>
%% Cell type:markdown id: tags:
## Introduction
### How to do the TP?
This [notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.
### The problem we'll deal with throughout the TPs
Any real number can be approximated by the ratio between two integers.
We will choose here to approximate any real `r` by an expression `numerator / 2^exponent`, where both `numerator` and `exponent` are integers.
The higher the numerator and exponent values, the more accurate the approximation can be. For example, 0.65 can be approximated successively by:
* 1 / 2<sup>1</sup> = 0.5
* 3 / 2<sup>2</sup> = 0.75
* 5 / 2<sup>3</sup> = 0.625
* ...
The highest possible numbers will therefore be chosen, within the limits set by the system, i.e. by the number of bits available to encode these numbers.
As part of the TP, the number of bits allowed to store the numerator will be arbitrarily fixed, and the effect on the accuracy of the approximation will be calculated. Note that if you have N bits to store an integer, the largest possible integer is 2<sup>N</sup> - 1.
The file you need to start is [provided](/notebooks/1-ProceduralProgramming/TP/initial_file.cpp) in the TP folder of ProceduralProgramming lectures.
The file you need to start is [provided](/notebooks/TP/1-ProceduralProgramming/initial_file.cpp) in the TP folder of ProceduralProgramming lectures.
%% Cell type:markdown id: tags:
### __EXERCICE 1: Adding a loop__
Write a loop that displays the like of above up to the 2<sup>8</sup> for 0.65.
_Expected result_:
0.65 ~ 1 / 2^1
0.65 ~ 3 / 2^2
0.65 ~ 5 / 2^3
0.65 ~ 10 / 2^4
0.65 ~ 21 / 2^5
0.65 ~ 42 / 2^6
0.65 ~ 83 / 2^7
0.65 ~ 166 / 2^8
%% Cell type:markdown id: tags:
### __EXERCICE 2: Adding a function__
Introduce in the previous program a function called `display_power_of_2_approx()` which takes as argument the actual value to be approximated. Modify the main program to call this function with values 0.65 and 0.35. The main program must be:
%% Cell type:code id: tags:
``` C++17
int main()
{
display_power_of_2_approx(.65);
display_power_of_2_approx(.35);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
_Expected result_:
0.65 ~ 1 / 2^1
0.65 ~ 3 / 2^2
0.65 ~ 5 / 2^3
0.65 ~ 10 / 2^4
0.65 ~ 21 / 2^5
0.65 ~ 42 / 2^6
0.65 ~ 83 / 2^7
0.65 ~ 166 / 2^8.
0.35 ~ 1 / 2^1
0.35 ~ 1 / 2^2
0.35 ~ 3 / 2^3
0.35 ~ 6 / 2^4
0.35 ~ 11 / 2^5
0.35 ~ 22 / 2^6
0.35 ~ 45 / 2^7
0.35 ~ 90 / 2^8
%% Cell type:markdown id: tags:
### __EXERCICE 3: compute the approximation__
Add in the `display_power_of_2_approx()` function the display of the approximate value, which is calculated by dividing each numerator by the power of two associated. Be careful, dividing an integer by an integer returns an integer: for instance 3 / 4 is 0. A division returns a real if one of the terms is real: 3. / 4 or `static_cast<double>`(3) / 4 is 0.75.
We will modify the display slightly so that the output looks like:
````
0.65 ~ 0.5 (1 / 2^1)
0.65 ~ 0.75 (3 / 2^2)
0.65 ~ 0.625 (5 / 2^3)
0.65 ~ 0.625 (10 / 2^4)
0.65 ~ 0.65625 (21 / 2^5)
0.65 ~ 0.65625 (42 / 2^6)
0.65 ~ 0.648438 (83 / 2^7)
0.65 ~ 0.648438 (166 / 2^8)
0.35 ~ 0.5 (1 / 2^1)
0.35 ~ 0.25 (1 / 2^2)
0.35 ~ 0.375 (3 / 2^3)
0.35 ~ 0.375 (6 / 2^4)
0.35 ~ 0.34375 (11 / 2^5)
0.35 ~ 0.34375 (22 / 2^6)
0.35 ~ 0.351562 (45 / 2^7)
0.35 ~ 0.351562 (90 / 2^8)
````
%% Cell type:markdown id: tags:
### __EXERCICE 4: Search for the best approximation for a given maximum numerator.__
The larger the numerator and the exponent to the denominator, the more accurate the approximation.
In `display_power_of_2_approx()`, modify the loop so that it looks for the best numerator / exponent pair, without the numerator exceeding a certain maximum value, passed as an argument to the function.
Keep the display only for this best solution, and add in this display the value of the maximum allowed numerator.
Use the following `main()` function to check it works:
%% Cell type:code id: tags:
``` C++17
int main()
{
display_power_of_2_approx(15, 0.65) ;
display_power_of_2_approx(255, 0.65) ;
display_power_of_2_approx(15, 0.35) ;
display_power_of_2_approx(255, 0.35) ;
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
Expected result is something like:
````
[With numerator < 15]: 0.65 ~ 0.625 (10/2^4)
[With numerator < 255]: 0.65 ~ 0.648438 (166/2^8)
[With numerator < 15]: 0.35 ~ 0.34375 (11/2^5)
[With numerator < 255]: 0.35 ~ 0.349609 (179/2^9)
````
%% Cell type:markdown id: tags:
### __EXERCICE 5: Computation of the maximum numerator as a function of the number of bits__
The highest usable value for the numerator depends on the number of bits used to represent this integer.
In `display_power_of_2_approx()` arguments, replace the argument designating the maximum value with an argument designating the maximum number of bits and correct the body of the function accordingly, using the `max_int()` function given below.
On display, replace the maximum numerator with the number of bits.
In the main program, make two loops that vary the number of bits from 2 to 8 in steps of 2, one that calls `display_power_of_2_approx()` for 0.65, and the other for 0.35.
%% Cell type:code id: tags:
``` C++17
// Maximum integer that might be represented with `Nbits` bits.
int max_int(int Nbits)
{
return (times_power_of_2(1, Nbits) - 1);
}
```
%% Cell type:markdown id: tags:
_Expected result_:
````
[With 2 bits]: 0.65 ~ 0.75 (3/2^2)
[With 4 bits]: 0.65 ~ 0.625 (10/2^4)
[With 6 bits]: 0.65 ~ 0.65625 (42/2^6)
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8)
[With 2 bits]: 0.35 ~ 0.375 (3/2^3)
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5)
[With 6 bits]: 0.35 ~ 0.351562 (45/2^7)
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9)
````
%% Cell type:markdown id: tags:
### __EXERCICE 6: moving display to a new intermediate function__
Currently, `display_power_of_2_approx()` is in charge of two different operations:
* Computing the values.
* Displaying them on screen.
It is often advisable to give one main functionality to a given function; we will thefore separate here the computation from the display.
Write a new function named `compute_power_of_2_approx()`, which computes the approximation itself and returns the numerator and the exponent as output arguments; this function will be called in `display_power_of_2_approx()`.
Output should remain the same!
%% Cell type:markdown id: tags:
### __EXERCICE 7: adding error in display__
Add in `display_power_of_2_approx()` the relative error of the approximation, computed by
````
(number - approx) / number
````
presented as a percentage and rounded to the nearest integer.
_Expected result_:
````
[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]
[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]
[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]
[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 0/100]
````
%% Cell type:markdown id: tags:
### __EXERCICE 8: Multiplication__
Write the `multiply()` function that calculates the approximate product of a real by an integer coefficient and returns an integer.
This function must approximate the real using the `compute_power_of_2_approx()` function above; the returned integer shall use `times_power_of_2()` function.
The arguments of `multiply()` are the maximum number of bits for approximation, the real and the integer coefficient.
The new main will be:
%% Cell type:code id: tags:
``` C++17
int main(int argc, char** argv)
{
static_cast<void>(argc); // to silence warning about unused argc - don't bother
static_cast<void>(argv); // to silence warning about unused argv - don't bother
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(Nbits, 0.65) ;
std::cout << std::endl;
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(Nbits, 0.35) ;
std::cout << std::endl;
for (int Nbits = 1; Nbits <= 8; ++Nbits)
{
double exact = 0.65 * 3515 + 0.35 * 4832;
int rounded = round_as_int(exact);
int approx = multiply(Nbits, 0.65, 3515) + multiply(Nbits, 0.35, 4832);
std::cout << "[With " << Nbits << " bits]: 0.65 * 3515 + 0.35 * 4832 = "
<< rounded << " ~ " << approx << std::endl;
}
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
_Expected result:_
````
[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]
[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]
[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]
[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 0/100]
[With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965
[With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448
[With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857
[With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967
[With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004
[With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968
````
%% Cell type:markdown id: tags:
### EXERCICE 9: display sum of two `multiply`
Exactly as we did previously in exercice 2, move the display of the sum of multiplication result in a dedicated function `display_sum()` (which will hence takes 5 arguments: number of bits, two reals and their associated integer coefficient).
New main will look like:
%% Cell type:code id: tags:
``` C++17
int main(int argc, char** argv)
{
static_cast<void>(argc); // to silence warning about unused argc - don't bother
static_cast<void>(argv); // to silence warning about unused argv - don't bother
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(0.65, Nbits);
std::cout << std::endl;
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(0.35, Nbits);
std::cout << std::endl;
for (int Nbits = 1; Nbits <= 8; ++Nbits)
display_multiply(Nbits, 0.65, 3515, 0.35, 4832);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
### __EXERCICE 10: print error in `display_sum()`__
Modify slightly the function defined above to add display of the error; we will express it over 1000.
_Expected result_:
````
[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]
[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]
[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]
[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [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:
### EXERCICE 11: function pointers
Create a `loop()` function that takes as an argument :
* An initial number of bits
* A final number of bits
* An increment to be applied to the number of bits
* A pointer to a function to be executed for each number of bits
You will need the following intermediate function to be able to use them in `loop()` (as a specific signature is expected):
%% Cell type:code id: tags:
``` C++17
void display_065(int Nbits)
{
display_power_of_2_approx(Nbits, 0.65);
}
void display_035(int Nbits)
{
display_power_of_2_approx(Nbits, 0.35);
}
void display_065_3515_035_4832(int Nbits)
{
display_sum(Nbits, 0.65, 3515, 0.35, 4832);
}
```
%% Cell type:code id: tags:
``` C++17
int main()
{
loop(2, 8, 2, display_065) ;
loop(2, 8, 2, display_035) ;
loop(1, 8, 1, display_065_3515_035_4832) ;
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2019_
_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