"### __EXERCISE 3: compute the approximation__\n",
"### __EXERCISE 3: Compute the approximation__\n",
"\n",
"Add in the `DisplayPowerOf2Approx()` 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.\n",
"\n",
...
...
@@ -163,7 +163,13 @@
"metadata": {},
"outputs": [],
"source": [
"// Maximum integer that might be represented with `nbits` bits.\n",
"/*!\n",
" * \\brief Maximum integer that might be represented with `nbits` bits.\n",
" * \n",
" * \\param[in] nbits Number of bits available.\n",
" *\n",
" * \\return Biggest integer that may be represented.\n",
" */ \n",
"int MaxInt(int nbits)\n",
"{ \n",
" return (TimesPowerOf2(1, nbits) - 1);\n",
...
...
@@ -174,6 +180,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**WARNING:** If you do not separate declaration and definition explicitly, `MaxInt()` must be located _before_ `DisplayPowerOf2Approx()`.\n",
"\n",
"Use the following `main()` function:"
]
},
...
...
@@ -238,7 +246,9 @@
"* Return the floating point approximation.\n",
"* Return (with reference parameters) the numerator and the exponent (that are displayed on screen).\n",
"\n",
"Output should remain the same!\n"
"Output should remain the same!\n",
"\n",
"**WARNING:** If you do not separate declaration and definition explicitly, `ComputePowerOf2Approx()` must be located _before_ `DisplayPowerOf2Approx()`.\n"
]
},
{
...
...
@@ -256,7 +266,8 @@
"presented as a percentage and rounded to the nearest integer. \n",
"\n",
"Absolute value may be computed with `std::fabs`, which is in header file `cmath`.\n",
" \n",
"\n",
" \n",
"*Expected result*:\n",
"\n",
"```\n",
...
...
%% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Procedural programming](./0-main.ipynb) - [Hands-on 2](./4b-hands-on.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<spanclass="tocSkip"></span></h1>
<divclass="toc"><ulclass="toc-item"><li><span><ahref="#EXERCISE-2:-Adding-a-function"data-toc-modified-id="EXERCISE-2:-Adding-a-function-1"><strong>EXERCISE 2: Adding a function</strong></a></span></li><li><span><ahref="#EXERCISE-3:-compute-the-approximation"data-toc-modified-id="EXERCISE-3:-compute-the-approximation-2"><strong>EXERCISE 3: compute the approximation</strong></a></span></li><li><span><ahref="#EXERCISE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator."data-toc-modified-id="EXERCISE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator.-3"><strong>EXERCISE 4: Search for the best approximation for a given maximum numerator.</strong></a></span></li><li><span><ahref="#EXERCISE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits"data-toc-modified-id="EXERCISE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits-4"><strong>EXERCISE 5: Computation of the maximum numerator as a function of the number of bits</strong></a></span></li><li><span><ahref="#EXERCISE-6:-moving-display-to-a-new-intermediate-function"data-toc-modified-id="EXERCISE-6:-moving-display-to-a-new-intermediate-function-5"><strong>EXERCISE 6: moving display to a new intermediate function</strong></a></span></li><li><span><ahref="#EXERCISE-7:-adding-error-in-display"data-toc-modified-id="EXERCISE-7:-adding-error-in-display-6"><strong>EXERCISE 7: adding error in display</strong></a></span></li></ul></div>
%% Cell type:markdown id: tags:
### __EXERCISE 2: Adding a function__
Introduce in the previous program a function called `DisplayPowerOf2Approx()` 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()
{
DisplayPowerOf2Approx(.65);
DisplayPowerOf2Approx(.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:
### __EXERCISE 3: compute the approximation__
### __EXERCISE 3: Compute the approximation__
Add in the `DisplayPowerOf2Approx()` 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:
### __EXERCISE 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 `DisplayPowerOf2Approx()`, 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()
{
DisplayPowerOf2Approx(15, 0.65);
DisplayPowerOf2Approx(255, 0.65);
DisplayPowerOf2Approx(15, 0.35);
DisplayPowerOf2Approx(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:
### __EXERCISE 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 `DisplayPowerOf2Approx()` arguments, replace the argument designating the maximum numerator with an argument designating the maximum number of bits and correct the body of the function accordingly, using the `MaxInt()` function given below.
On display, replace the maximum numerator with the number of bits.
%% Cell type:code id: tags:
``` C++17
// Maximum integer that might be represented with `nbits` bits.
/*!
* \brief Maximum integer that might be represented with `nbits` bits.
*
* \param[in] nbits Number of bits available.
*
* \return Biggest integer that may be represented.
*/
int MaxInt(int nbits)
{
return (TimesPowerOf2(1, nbits) - 1);
}
```
%% Cell type:markdown id: tags:
**WARNING:** If you do not separate declaration and definition explicitly, `MaxInt()` must be located _before_ `DisplayPowerOf2Approx()`.
Use the following `main()` function:
%% 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)
DisplayPowerOf2Approx(nbits, 0.65);
std::cout << std::endl;
for (int nbits = 2; nbits <= 8; nbits += 2)
DisplayPowerOf2Approx(nbits, 0.35);
return EXIT_SUCCESS;
}
```
%% 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:
### __EXERCISE 6: moving display to a new intermediate function__
Currently, `DisplayPowerOf2Approx()` 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 therefore separate here the computation from the display.
Write a new function named `ComputePowerOf2Approx()` that will be called in `DisplayPowerOf2Approx()`.
This new function should:
* Return the floating point approximation.
* Return (with reference parameters) the numerator and the exponent (that are displayed on screen).
Output should remain the same!
**WARNING:** If you do not separate declaration and definition explicitly, `ComputePowerOf2Approx()` must be located _before_ `DisplayPowerOf2Approx()`.
%% Cell type:markdown id: tags:
### __EXERCISE 7: adding error in display__
Add in `DisplayPowerOf2Approx()` the relative error of the approximation, computed by
```
|number - approx| / number
```
presented as a percentage and rounded to the nearest integer.
Absolute value may be computed with `std::fabs`, which is in header file `cmath`.