Mentions légales du service

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

Merge branch '64_fix_naming' into 'master'

#64 Fix naming not properly propagated in hands on notebooks.

See merge request formations/cpp/gettingstartedwithmoderncpp!59
parents 8eb3c9f3 381bc11e
No related branches found
No related tags found
1 merge request!59#64 Fix naming not properly propagated in hands on notebooks.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 7](./4b-hands-on.ipynb) # [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 7](./4b-hands-on.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#EXERCISE-16:-transform-struct-PowerOfTwoApprox-into-a-class" data-toc-modified-id="EXERCISE-16:-transform-struct-PowerOfTwoApprox-into-a-class-1">EXERCISE 16: transform struct <code>PowerOfTwoApprox</code> into a class</a></span></li><li><span><a href="#EXERCISE-17:-transform-Multiply()-into-a-method-Multiply()-of-PowerOfTwoApprox" data-toc-modified-id="EXERCISE-17:-transform-Multiply()-into-a-method-Multiply()-of-PowerOfTwoApprox-2">EXERCISE 17: transform <code>Multiply()</code> into a method <code>Multiply()</code> of <code>PowerOfTwoApprox</code></a></span></li><li><span><a href="#EXERCISE-18:-transform-DisplayPowerOf2Approx()-into-a-class" data-toc-modified-id="EXERCISE-18:-transform-DisplayPowerOf2Approx()-into-a-class-3">EXERCISE 18: transform <code>DisplayPowerOf2Approx()</code> into a class</a></span></li><li><span><a href="#EXERCISE-19:-transform-DisplayMultiply()-into-a-class" data-toc-modified-id="EXERCISE-19:-transform-DisplayMultiply()-into-a-class-4">EXERCISE 19: transform <code>DisplayMultiply()</code> into a class</a></span></li><li><span><a href="#EXERCISE-20:-introduce-common-PrintLine()-function-for-outputs" data-toc-modified-id="EXERCISE-20:-introduce-common-PrintLine()-function-for-outputs-5">EXERCISE 20: introduce common <code>PrintLine()</code> function for outputs</a></span></li></ul></div> <div class="toc"><ul class="toc-item"><li><span><a href="#EXERCISE-16:-transform-struct-PowerOfTwoApprox-into-a-class" data-toc-modified-id="EXERCISE-16:-transform-struct-PowerOfTwoApprox-into-a-class-1">EXERCISE 16: transform struct <code>PowerOfTwoApprox</code> into a class</a></span></li><li><span><a href="#EXERCISE-17:-transform-Multiply()-into-a-method-Multiply()-of-PowerOfTwoApprox" data-toc-modified-id="EXERCISE-17:-transform-Multiply()-into-a-method-Multiply()-of-PowerOfTwoApprox-2">EXERCISE 17: transform <code>Multiply()</code> into a method <code>Multiply()</code> of <code>PowerOfTwoApprox</code></a></span></li><li><span><a href="#EXERCISE-18:-transform-DisplayPowerOf2Approx()-into-a-class" data-toc-modified-id="EXERCISE-18:-transform-DisplayPowerOf2Approx()-into-a-class-3">EXERCISE 18: transform <code>DisplayPowerOf2Approx()</code> into a class</a></span></li><li><span><a href="#EXERCISE-19:-transform-DisplaySumOfMultiply()-into-a-class" data-toc-modified-id="EXERCISE-19:-transform-DisplaySumOfMultiply()-into-a-class-4">EXERCISE 19: transform <code>DisplaySumOfMultiply()</code> into a class</a></span></li><li><span><a href="#EXERCISE-20:-introduce-common-PrintLine()-function-for-outputs" data-toc-modified-id="EXERCISE-20:-introduce-common-PrintLine()-function-for-outputs-5">EXERCISE 20: introduce common <code>PrintLine()</code> function for outputs</a></span></li></ul></div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 16: transform struct `PowerOfTwoApprox` into a class ### EXERCISE 16: transform struct `PowerOfTwoApprox` into a class
Make `PowerOfTwoApprox` into a class, with proper encapsulation: Make `PowerOfTwoApprox` into a class, with proper encapsulation:
* Both data attributes should be made private. * Both data attributes should be made private.
* Constant accessors will therefore be needed (non-constant ones should not be required here) * Constant accessors will therefore be needed (non-constant ones should not be required here)
Expected output is the same as previously. Expected output is the same as previously.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 17: transform `Multiply()` into a method `Multiply()` of `PowerOfTwoApprox` ### EXERCISE 17: transform `Multiply()` into a method `Multiply()` of `PowerOfTwoApprox`
The method will take as argument only the integer coefficient. The method will take as argument only the integer coefficient.
`DisplayMultiply()` will of course need also some light rewriting to accommodate that change. `DisplaySumOfMultiply()` will of course need also some light rewriting to accommodate that change.
Expected output is the same as previously. Expected output is the same as previously.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 18: transform `DisplayPowerOf2Approx()` into a class ### EXERCISE 18: transform `DisplayPowerOf2Approx()` into a class
Create a class `TestDisplayPowerOfTwoApprox` which will be in charge of printing the display for the 0.65 and 0.35 values. Create a class `TestDisplayPowerOfTwoApprox` which will be in charge of printing the display for the 0.65 and 0.35 values.
Use two methods in this class: Use two methods in this class:
* A public method `Do()` which will call the test for 0.65 and 0.35; this method will take the number of bits as argument. * A public method `Do()` which will call the test for 0.65 and 0.35; this method will take the number of bits as argument.
* A private method `Display()` which will provide the display for a given double value (and will therefore be called twice: once for 0.65 and once for 0.35). * A private method `Display()` which will provide the display for a given double value (and will therefore be called twice: once for 0.65 and once for 0.35).
New main should look like: New main should look like:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static_cast<void>(argc); // to silence warning about unused argc - don't bother 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 static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayPowerOfTwoApprox test_display_approx; TestDisplayPowerOfTwoApprox test_display_approx;
for (int nbits = 2; nbits <= 8; nbits += 2) for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx.Do(nbits); test_display_approx.Do(nbits);
std::cout << std::endl; std::cout << std::endl;
for (int nbits = 1; nbits <= 8; ++nbits) for (int nbits = 1; nbits <= 8; ++nbits)
DisplayMultiply(nbits, 0.65, 3515, 0.35, 4832); DisplaySumOfMultiply(nbits, 0.65, 3515, 0.35, 4832);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Output will be ordered differently: Output will be ordered differently:
```` ````
[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100] [With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]
[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100] [With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100] [With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100] [With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]
[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100] [With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]
[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100] [With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100] [With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [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 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 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 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 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 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 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 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] [With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2/1000]
```` ````
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 19: transform `DisplayMultiply()` into a class ### EXERCISE 19: transform `DisplaySumOfMultiply()` into a class
Likewise, create a class `TestDisplayMultiply` which will be in charge of printing the display for 0.65 * 3515 + 0.35 * 4832 with public method `Do()` and private method `Display()` which will takes 5 arguments: Likewise, create a class `TestDisplaySumOfMultiply` which will be in charge of printing the display for 0.65 * 3515 + 0.35 * 4832 with public method `Do()` and private method `Display()` which will takes 5 arguments:
* Number of bits. * Number of bits.
* The two floating point values. * The two floating point values.
* Their integer coefficient. * Their integer coefficient.
New `main()` is: New `main()` is:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static_cast<void>(argc); // to silence warning about unused argc - don't bother 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 static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayPowerOfTwoApprox test_display_approx; TestDisplayPowerOfTwoApprox test_display_approx;
for (int nbits = 2; nbits <= 8; nbits += 2) for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx.Do(nbits); test_display_approx.Do(nbits);
std::cout << std::endl; std::cout << std::endl;
TestDisplayMultiply test_DisplayMultiply; TestDisplaySumOfMultiply test_display_sum_of_multiply;
for (int nbits = 1; nbits <= 8; ++nbits) for (int nbits = 1; nbits <= 8; ++nbits)
test_DisplayMultiply.Do(nbits); test_display_sum_of_multiply.Do(nbits);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 20: introduce common `PrintLine()` function for outputs ### EXERCISE 20: introduce common `PrintLine()` function for outputs
Both `TestDisplay` classes are rather similar in the line in charge of printing content on standard output - so we would like to uniformize the implementation. Both `TestDisplay` classes are rather similar in the line in charge of printing content on standard output - so we would like to uniformize the implementation.
We will therefore introduce a `PrintLine()` function which will be in charge of printing the line for a given number of bits. We will therefore introduce a `PrintLine()` function which will be in charge of printing the line for a given number of bits.
At the moment, we will renege the sound principle of separating the functionalities (humor me for the moment...) and this function will: At the moment, we will renege the sound principle of separating the functionalities (humor me for the moment...) and this function will:
* Take as arguments the number of bits, the exact actual number (obtained through usual floating-point arithmetic) and the approximation of this number through our representation. * Take as arguments the number of bits, the exact actual number (obtained through usual floating-point arithmetic) and the approximation of this number through our representation.
* Compute the error with a resolution also given as argument ((i.e. the maximum index against which error is expressed - 100 and 1000 respectively up to now). * Compute the error with a resolution also given as argument ((i.e. the maximum index against which error is expressed - 100 and 1000 respectively up to now).
However there are subtleties in the way the lines are displayed: the parts in red is supplementary text that vary depending on the call site: However there are subtleties in the way the lines are displayed: the parts in red is supplementary text that vary depending on the call site:
[With 2 bits]: 0.65 ~ 0.75 <font color="red">(3/2^2)</font> [error = 15/100] [With 2 bits]: 0.65 ~ 0.75 <font color="red">(3/2^2)</font> [error = 15/100]
[With 1 bits]: <font color="red">0.65 * 3515 + 0.35 * 4832 = </font> 3976 ~ 2965 [error = 254/1000] [With 1 bits]: <font color="red">0.65 * 3515 + 0.35 * 4832 = </font> 3976 ~ 2965 [error = 254/1000]
So to do that you will need two strings arguments to provide the possibility to customize the line at the two locations pointed out in red (to achieve this you may need a reminder of [how to convert a number into a string](../1-ProceduralProgramming/6-Streams.ipynb#Conversion)). So to do that you will need two strings arguments to provide the possibility to customize the line at the two locations pointed out in red (to achieve this you may need a reminder of [how to convert a number into a string](../1-ProceduralProgramming/6-Streams.ipynb#Conversion)).
Last subtlety: for the `DisplayMultiply` case we round the exact value to an integer, but that would break the output for the `TestDisplayPowerOfTwoApprox` cases... So we introduce an enum class which will act as a boolean: Last subtlety: for the `DisplaySumOfMultiply` case we round the exact value to an integer, but that would break the output for the `TestDisplayPowerOfTwoApprox` cases... So we introduce an enum class which will act as a boolean:
```` ````
enum class RoundToInteger { no, yes }; enum class RoundToInteger { no, yes };
```` ````
To sum up, the signature or `PrintLine()` should be: To sum up, the signature or `PrintLine()` should be:
```` ````
void PrintLine(int nbits, double exact, double approx, int maximum_error_index, void PrintLine(int nbits, double exact, double approx, int maximum_error_index,
std::string optional_string1, std::string optional_string2, std::string optional_string1, std::string optional_string2,
RoundToInteger round_to_integer); RoundToInteger round_to_integer);
```` ````
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md) [© Copyright](../COPYRIGHT.md)
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 8](./7b-hands-on.ipynb) # [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 8](./7b-hands-on.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#EXERCISE-21:-base-class-TestDisplay" data-toc-modified-id="EXERCISE-21:-base-class-TestDisplay-1">EXERCISE 21: base class <code>TestDisplay</code></a></span></li><li><span><a href="#EXERCISE-22:-inherit-from-TestDisplayPowerOfTwoApprox" data-toc-modified-id="EXERCISE-22:-inherit-from-TestDisplayPowerOfTwoApprox-2">EXERCISE 22: inherit from <code>TestDisplayPowerOfTwoApprox</code></a></span></li><li><span><a href="#EXERCISE-23:-Toward-a-TestDisplayContainer-class" data-toc-modified-id="EXERCISE-23:-Toward-a-TestDisplayContainer-class-3">EXERCISE 23: Toward a <code>TestDisplayContainer</code> class</a></span></li><li><span><a href="#EXERCISE-24:-dynamic-allocation-of-array" data-toc-modified-id="EXERCISE-24:-dynamic-allocation-of-array-4">EXERCISE 24: dynamic allocation of array</a></span></li><li><span><a href="#EXERCISE-25:-transform-TestDisplayContainer::Do()-into-a-free-function" data-toc-modified-id="EXERCISE-25:-transform-TestDisplayContainer::Do()-into-a-free-function-5">EXERCISE 25: transform <code>TestDisplayContainer::Do()</code> into a free function</a></span></li></ul></div> <div class="toc"><ul class="toc-item"><li><span><a href="#EXERCISE-21:-base-class-TestDisplay" data-toc-modified-id="EXERCISE-21:-base-class-TestDisplay-1">EXERCISE 21: base class <code>TestDisplay</code></a></span></li><li><span><a href="#EXERCISE-22:-inherit-from-TestDisplayPowerOfTwoApprox" data-toc-modified-id="EXERCISE-22:-inherit-from-TestDisplayPowerOfTwoApprox-2">EXERCISE 22: inherit from <code>TestDisplayPowerOfTwoApprox</code></a></span></li><li><span><a href="#EXERCISE-23:-Toward-a-TestDisplayContainer-class" data-toc-modified-id="EXERCISE-23:-Toward-a-TestDisplayContainer-class-3">EXERCISE 23: Toward a <code>TestDisplayContainer</code> class</a></span></li><li><span><a href="#EXERCISE-24:-dynamic-allocation-of-array" data-toc-modified-id="EXERCISE-24:-dynamic-allocation-of-array-4">EXERCISE 24: dynamic allocation of array</a></span></li><li><span><a href="#EXERCISE-25:-transform-TestDisplayContainer::Do()-into-a-free-function" data-toc-modified-id="EXERCISE-25:-transform-TestDisplayContainer::Do()-into-a-free-function-5">EXERCISE 25: transform <code>TestDisplayContainer::Do()</code> into a free function</a></span></li></ul></div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 21: base class `TestDisplay` ### EXERCISE 21: base class `TestDisplay`
Create a base class `TestDisplay` from which both `TestDisplayPowerOfTwoApprox` and `TestDisplaySum` will inherit publicly. Create a base class `TestDisplay` from which both `TestDisplayPowerOfTwoApprox` and `TestDisplaySum` will inherit publicly.
This class: This class:
* Should get a constructor which sets the resolution. * Should get a constructor which sets the resolution.
* Includes a protected method named `PrintLine()` that will replace the `PrintLine()` we introduced in previous exercise. * Includes a protected method named `PrintLine()` that will replace the `PrintLine()` we introduced in previous exercise.
The constructors of derived classes will of course have to be modified accordingly: so far we relied on default ones. The constructors of derived classes will of course have to be modified accordingly: so far we relied on default ones.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 22: inherit from `TestDisplayPowerOfTwoApprox` ### EXERCISE 22: inherit from `TestDisplayPowerOfTwoApprox`
We would like to get back former output in which we got first all outputs for 0.65, then all the ones for 0.35. We would like to get back former output in which we got first all outputs for 0.65, then all the ones for 0.35.
To do so, we will create two classes `TestDisplayPowerOfTwoApprox065` and `TestDisplayPowerOfTwoApprox035` that inherits from `TestDisplayPowerOfTwoApprox`. To do so, we will create two classes `TestDisplayPowerOfTwoApprox065` and `TestDisplayPowerOfTwoApprox035` that inherits from `TestDisplayPowerOfTwoApprox`.
Of course, we still abide by the DRY principle and we want to specialize only the code related to `Do()` method. Of course, we still abide by the DRY principle and we want to specialize only the code related to `Do()` method.
The `main()` to use: The `main()` to use:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static_cast<void>(argc); // to silence warning about unused argc - don't bother 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 static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayPowerOfTwoApprox065 test_display_approx065(100); TestDisplayPowerOfTwoApprox065 test_display_approx065(100);
for (int nbits = 2; nbits <= 8; nbits += 2) for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx065.Do(nbits); test_display_approx065.Do(nbits);
std::cout << std::endl; std::cout << std::endl;
TestDisplayPowerOfTwoApprox035 test_display_approx035(100); TestDisplayPowerOfTwoApprox035 test_display_approx035(100);
for (int nbits = 2; nbits <= 8; nbits += 2) for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx035.Do(nbits); test_display_approx035.Do(nbits);
std::cout << std::endl; std::cout << std::endl;
TestDisplayMultiply test_DisplayMultiply(1000); TestDisplaySumOfMultiply test_display_sum_of_multiply(1000);
for (int nbits = 1; nbits <= 8; ++nbits) for (int nbits = 1; nbits <= 8; ++nbits)
test_DisplayMultiply.Do(nbits); test_display_sum_of_multiply.Do(nbits);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
_Expected output:_ _Expected output:_
```` ````
[With 2 bits]: 0.65 ~ 0.75 (3 / 2^2) [error = 15/100] [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 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 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 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 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 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 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 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 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 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 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 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 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 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 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] [With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2/1000]
```` ````
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 23: Toward a `TestDisplayContainer` class ### EXERCISE 23: Toward a `TestDisplayContainer` class
We would like to introduce an object which purpose is to store the various `TestDisplay` class and call for each of them the `Do` method. We would like to introduce an object which purpose is to store the various `TestDisplay` class and call for each of them the `Do` method.
The declaration of the class should look like: The declaration of the class should look like:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
class TestDisplayContainer class TestDisplayContainer
{ {
public: public:
//! Add a new test_display_register. //! Add a new test_display_register.
//! At each call, the item to be registered is put at the first available position and internal current_position_ //! At each call, the item to be registered is put at the first available position and internal current_position_
//! is incremented. If the end-user attempts to register more than three items, the Error() function is called. //! is incremented. If the end-user attempts to register more than three items, the Error() function is called.
void Register(TestDisplay* test_display); void Register(TestDisplay* test_display);
//! For each container stored, loop oover all those bits and print the result on screen. //! For each container stored, loop oover all those bits and print the result on screen.
void Do(int initial_Nbit, int final_Nbit, int increment_Nbit) const; void Do(int initial_Nbit, int final_Nbit, int increment_Nbit) const;
private: private:
//! List of all known `TestDisplay` objects. //! List of all known `TestDisplay` objects.
TestDisplay* list_[3]; TestDisplay* list_[3];
//! Index to place the next register object. If '3', no more object may be registered. //! Index to place the next register object. If '3', no more object may be registered.
int current_position_ {}; int current_position_ {};
}; };
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
You will need to add a sanity check in constructor; in case of failure use at the moment the following function: You will need to add a sanity check in constructor; in case of failure use at the moment the following function:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
//! Function for error handling. We will see later how to fulfill the same functionality more properly. //! Function for error handling. We will see later how to fulfill the same functionality more properly.
[[noreturn]] void Error(std::string explanation) [[noreturn]] void Error(std::string explanation)
{ {
std::cout << "ERROR: " << explanation << std::endl; std::cout << "ERROR: " << explanation << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The `main()` to use is: The `main()` to use is:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static_cast<void>(argc); // to silence warning about unused argc - don't bother 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 static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayContainer container; TestDisplayContainer container;
container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
container.Register(new TestDisplayMultiply(10000)); container.Register(new TestDisplaySumOfMultiply(10000));
container.Do(4, 16, 4); container.Do(4, 16, 4);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
_Expected result:_ _Expected result:_
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000] [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 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 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 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 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 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 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 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000] [With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000] [With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000]
[With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 24: dynamic allocation of array ### EXERCISE 24: dynamic allocation of array
Instead of setting an arbitrary size of 3, we will now add a size dynamically in `TestDisplayContainer` constructor; the internal storage will now be: Instead of setting an arbitrary size of 3, we will now add a size dynamically in `TestDisplayContainer` constructor; the internal storage will now be:
```` ````
TestDisplay** test_display_list_; TestDisplay** test_display_list_;
```` ````
meaning we will store an array of pointers (don't worry, we will see later how to avoid such monstruosities... but it is useful nonetheless to try them a bit). meaning we will store an array of pointers (don't worry, we will see later how to avoid such monstruosities... but it is useful nonetheless to try them a bit).
Constructor must now: Constructor must now:
* Allocate the array of `TestDisplay*` with a **capacity** given as its argument (the capacity being the number of elements that *might* be stored inside - we'll see the chosen name is not a whim). * Allocate the array of `TestDisplay*` with a **capacity** given as its argument (the capacity being the number of elements that *might* be stored inside - we'll see the chosen name is not a whim).
* Keep track of the capacity (the related data attribute should be constant: we don't intend to modify the capacity of the array after construction). * Keep track of the capacity (the related data attribute should be constant: we don't intend to modify the capacity of the array after construction).
* Set each element to `nullptr`. * Set each element to `nullptr`.
Destructor must of course take care of deallocating properly the memory. Destructor must of course take care of deallocating properly the memory.
**NOTE:** To avoid a warning you should use `std::size_t` when allocating the array: this is the type used for array (which is in all compilers I've used an alias to `unsigned long` but standard dictates you should use `std::size_t`). **NOTE:** To avoid a warning you should use `std::size_t` when allocating the array: this is the type used for array (which is in all compilers I've used an alias to `unsigned long` but standard dictates you should use `std::size_t`).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 25: transform `TestDisplayContainer::Do()` into a free function ### EXERCISE 25: transform `TestDisplayContainer::Do()` into a free function
We probably went a bridge too far: it is useful to provide an object which contains several `TestDisplay` together, but making it take in charge the loop might not be that good an idea (in a real program you might for instance interact with this container by another mean than the pre-defined loop). We probably went a bridge too far: it is useful to provide an object which contains several `TestDisplay` together, but making it take in charge the loop might not be that good an idea (in a real program you might for instance interact with this container by another mean than the pre-defined loop).
Replace the `Do()` method by a free function with signature: Replace the `Do()` method by a free function with signature:
```` ````
void Loop(int initial_Nbit, int final_Nbit, int increment_Nbit, const TestDisplayContainer& container) void Loop(int initial_Nbit, int final_Nbit, int increment_Nbit, const TestDisplayContainer& container)
```` ````
To do so, you will need to add several methods to `TestDisplayContainer`: To do so, you will need to add several methods to `TestDisplayContainer`:
- A method that returns the **size** (i.e. the number of non nullptr `TestDisplay*` stored), which will be required to loop over the relevant elements. - A method that returns the **size** (i.e. the number of non nullptr `TestDisplay*` stored), which will be required to loop over the relevant elements.
- A method to access the `i`-th element stored in the table. Signature might be: - A method to access the `i`-th element stored in the table. Signature might be:
```` ````
const TestDisplay& GetElement(std::size_t i) const const TestDisplay& GetElement(std::size_t i) const
```` ````
(but others are also possible - you may prefer to return a pointer rather than a reference). (but others are also possible - you may prefer to return a pointer rather than a reference).
New `main()` is: New `main()` is:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static_cast<void>(argc); // to silence warning about unused argc - don't bother 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 static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayContainer container(3); TestDisplayContainer container(3);
container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
container.Register(new TestDisplayMultiply(10000)); container.Register(new TestDisplaySumOfMultiply(10000));
Loop(4, 16, 4, container); Loop(4, 16, 4, container);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md) [© Copyright](../COPYRIGHT.md)
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Templates](./0-main.ipynb) - [Hands-on 12](./1b-hands-on.ipynb) # [Getting started in C++](./) - [Templates](./0-main.ipynb) - [Hands-on 12](./1b-hands-on.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <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="#Context:-when-int-is-not-enough" data-toc-modified-id="Context:-when-int-is-not-enough-2">Context: when <code>int</code> is not enough</a></span></li><li><span><a href="#EXERCISE-31:-make-PowerOfTwoApprox-a-template-class" data-toc-modified-id="EXERCISE-31:-make-PowerOfTwoApprox-a-template-class-3">EXERCISE 31: make <code>PowerOfTwoApprox</code> a template class</a></span></li><li><span><a href="#EXERCISE-32:-follow-the-thread..." data-toc-modified-id="EXERCISE-32:-follow-the-thread...-4">EXERCISE 32: follow the thread...</a></span></li></ul></div> <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="#Context:-when-int-is-not-enough" data-toc-modified-id="Context:-when-int-is-not-enough-2">Context: when <code>int</code> is not enough</a></span></li><li><span><a href="#EXERCISE-31:-make-PowerOfTwoApprox-a-template-class" data-toc-modified-id="EXERCISE-31:-make-PowerOfTwoApprox-a-template-class-3">EXERCISE 31: make <code>PowerOfTwoApprox</code> a template class</a></span></li><li><span><a href="#EXERCISE-32:-follow-the-thread..." data-toc-modified-id="EXERCISE-32:-follow-the-thread...-4">EXERCISE 32: follow the thread...</a></span></li></ul></div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Introduction ### Introduction
[This notebook](../HandsOn/HowTo.ipynb) explains very briefly your options to run the hands-ons. [This notebook](../HandsOn/HowTo.ipynb) explains very briefly your options to run the hands-ons.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Context: when `int` is not enough ### Context: when `int` is not enough
So far, we have not put much stress on our representation: So far, we have not put much stress on our representation:
- We have always used positive values (spoiler: negative don't work...) - We have always used positive values (spoiler: negative don't work...)
- We have also never try to reach the limit of the integer representation. - We have also never try to reach the limit of the integer representation.
If we do that and ask the loop up to 32 bits, we'll see things fall apart (obviously faster with the sum of two products, as we handle greater values). If we do that and ask the loop up to 32 bits, we'll see things fall apart (obviously faster with the sum of two products, as we handle greater values).
We'll see in the next chapter how to deal with errors, but first we will try to fix the 32 bits case to just change the internal integer representation we use. We'll see in the next chapter how to deal with errors, but first we will try to fix the 32 bits case to just change the internal integer representation we use.
We will therefore add a degree of freedom and let the end user choose the type of integer to use through the use of a template. We will therefore add a degree of freedom and let the end user choose the type of integer to use through the use of a template.
Replacing everything in one step is very error-prone and is definitively not what I do: I really recommend to change part of it, do a commit (in a real project) and thus proceed incrementally until you reach the target state. Replacing everything in one step is very error-prone and is definitively not what I do: I really recommend to change part of it, do a commit (in a real project) and thus proceed incrementally until you reach the target state.
Compiler is really your friend here: make sure implicit conversions deliver a warning helps you to check whether you didn't forget a substitution somewhere (compiler warnings will be dealt in a [further notebook](../6-InRealEnvironment/3-Compilers.ipynb); in the hands-ons the one is activated in the CMake, and if you're using an online compiler utility make sure there is `-Wconversion` on the command line). Compiler is really your friend here: make sure implicit conversions deliver a warning helps you to check whether you didn't forget a substitution somewhere (compiler warnings will be dealt in a [further notebook](../6-InRealEnvironment/3-Compilers.ipynb); in the hands-ons the one is activated in the CMake, and if you're using an online compiler utility make sure there is `-Wconversion` on the command line).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 31: make `PowerOfTwoApprox` a template class ### EXERCISE 31: make `PowerOfTwoApprox` a template class
Transform the type of `PowerOfTwoApprox::numerator_ ` into a class template parameter. Transform the type of `PowerOfTwoApprox::numerator_ ` into a class template parameter.
Only this attribute will be modified: the exponent and the number of bits remain `int`. Only this attribute will be modified: the exponent and the number of bits remain `int`.
Make sure to modify: Make sure to modify:
* The type of the data attribute. * The type of the data attribute.
* The type returned by the `GetNumerator()` method. * The type returned by the `GetNumerator()` method.
In the `TestDisplay` classes, we will for the moment keep instantiating the version with `int` (remember: we proceed with incremental steps). In the `TestDisplay` classes, we will for the moment keep instantiating the version with `int` (remember: we proceed with incremental steps).
We will start with an 'easy' case and call the instantiation for a `long`; warning conversions are fully expected (see explanation above). We will start with an 'easy' case and call the instantiation for a `long`; warning conversions are fully expected (see explanation above).
_Expected results (that don't fix anything to the issue found in preamble so far):_ _Expected results (that don't fix anything to the issue found in preamble so far):_
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000] [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 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 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 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 9/1000000]
[With 20 bits]: 0.65 ~ 0.65 (681574/2^20) [error = 1/1000000] [With 20 bits]: 0.65 ~ 0.65 (681574/2^20) [error = 1/1000000]
[With 24 bits]: 0.65 ~ 0.65 (10905190/2^24) [error = 0/1000000] [With 24 bits]: 0.65 ~ 0.65 (10905190/2^24) [error = 0/1000000]
[With 28 bits]: 0.65 ~ 0.65 (174483046/2^28) [error = 0/1000000] [With 28 bits]: 0.65 ~ 0.65 (174483046/2^28) [error = 0/1000000]
[With 32 bits]: 0.65 ~ 1 (1/2^0) [error = 538462/1000000] [With 32 bits]: 0.65 ~ 1 (1/2^0) [error = 538462/1000000]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 17857/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 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 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 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]
[With 20 bits]: 0.35 ~ 0.35 (734003/2^21) [error = 0/1000000] [With 20 bits]: 0.35 ~ 0.35 (734003/2^21) [error = 0/1000000]
[With 24 bits]: 0.35 ~ 0.35 (11744051/2^25) [error = 0/1000000] [With 24 bits]: 0.35 ~ 0.35 (11744051/2^25) [error = 0/1000000]
[With 28 bits]: 0.35 ~ 0.35 (187904819/2^29) [error = 0/1000000] [With 28 bits]: 0.35 ~ 0.35 (187904819/2^29) [error = 0/1000000]
[With 32 bits]: 0.35 ~ 0 (0/2^0) [error = 1000000/1000000] [With 32 bits]: 0.35 ~ 0 (0/2^0) [error = 1000000/1000000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000] [With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000] [With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000]
[With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 20 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ -2167 [error = 15450/10000] [With 20 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ -2167 [error = 15450/10000]
[With 24 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 8 [error = 9980/10000] [With 24 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 8 [error = 9980/10000]
[With 28 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 0 [error = 10000/10000] [With 28 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 0 [error = 10000/10000]
[With 32 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3515 [error = 1159/10000] [With 32 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3515 [error = 1159/10000]
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### EXERCISE 32: follow the thread... ### EXERCISE 32: follow the thread...
Your compiler should not be happy and tell you something like (here clang output with unfortunately the colors lost): Your compiler should not be happy and tell you something like (here clang output with unfortunately the colors lost):
```` ````
../exercise31.cpp:84:49: warning: implicit conversion loses integer precision: 'long' to 'int' [-Wshorten-64-to-32] ../exercise31.cpp:84:49: warning: implicit conversion loses integer precision: 'long' to 'int' [-Wshorten-64-to-32]
return TimesPowerOf2(approx.GetNumerator() * coefficient, -approx.GetExponent()); return TimesPowerOf2(approx.GetNumerator() * coefficient, -approx.GetExponent());
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
../exercise31.cpp:362:64: note: in instantiation of function template specialization 'operator*<long>' requested here ../exercise31.cpp:362:64: note: in instantiation of function template specialization 'operator*<long>' requested here
int approx = approximation1 * coefficient1 + coefficient2 * approximation2; int approx = approximation1 * coefficient1 + coefficient2 * approximation2;
```` ````
Let's humor the compiler and 'propagate' the template... which will not be a trivial journey: Let's humor the compiler and 'propagate' the template... which will not be a trivial journey:
* You will first have to make your own operator* template functions. * You will first have to make your own operator* template functions.
* As the operator is used directly in `TestDisplayMultiply`, you will also have to make that class a template class. * As the operator is used directly in `TestDisplaySumOfMultiply`, you will also have to make that class a template class.
At this point the code should be able to compile... but there are still loose ends, as your compiler will tell you (more or less clearly): At this point the code should be able to compile... but there are still loose ends, as your compiler will tell you (more or less clearly):
* `TimesPowerOf2()` should also be transformed into a template function. Therefore `MaxInt()` should as well. * `TimesPowerOf2()` should also be transformed into a template function. Therefore `MaxInt()` should as well.
* `RoundAsInt()` should also be modified * `RoundAsInt()` should also be modified
* And also `HelperComputePowerOf2Approx()` if you are using the proposed solution. * And also `HelperComputePowerOf2Approx()` if you are using the proposed solution.
* And finally `TestDisplay::PrintLine()` as well. At the moment, keep hardcoding the type for `TestDisplayPowerOfTwoApprox` which is not (yet) a template class. * And finally `TestDisplay::PrintLine()` as well. At the moment, keep hardcoding the type for `TestDisplayPowerOfTwoApprox` which is not (yet) a template class.
The code should at this point compile again... The code should at this point compile again...
But there is still a line which might be wrong (unless you were very cautious) without compiler warning: make sure the template argument is used in `PowerOfTwoApprox<IntT>::operator double`. This one was tricky as the code was But there is still a line which might be wrong (unless you were very cautious) without compiler warning: make sure the template argument is used in `PowerOfTwoApprox<IntT>::operator double`. This one was tricky as the code was
```` ````
int denominator = TimesPowerOf2(1, exponent_); int denominator = TimesPowerOf2(1, exponent_);
```` ````
which doesn't have to trigger a warning: `1` is an `int`... So the `int` specialization of `TimesPowerOf2`, and that is used to compute the floating point value returned! And you may end up with an unwanted `inf` instead of the expected numeric value. This is yet another reminder that magic numbers are dangerous, even if they look as innocuous as a 1... which doesn't have to trigger a warning: `1` is an `int`... So the `int` specialization of `TimesPowerOf2`, and that is used to compute the floating point value returned! And you may end up with an unwanted `inf` instead of the expected numeric value. This is yet another reminder that magic numbers are dangerous, even if they look as innocuous as a 1...
_Expected results (with `long`):_ _Expected results (with `long`):_
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000] [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 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 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 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 9/1000000]
[With 20 bits]: 0.65 ~ 0.65 (681574/2^20) [error = 1/1000000] [With 20 bits]: 0.65 ~ 0.65 (681574/2^20) [error = 1/1000000]
[With 24 bits]: 0.65 ~ 0.65 (10905190/2^24) [error = 0/1000000] [With 24 bits]: 0.65 ~ 0.65 (10905190/2^24) [error = 0/1000000]
[With 28 bits]: 0.65 ~ 0.65 (174483046/2^28) [error = 0/1000000] [With 28 bits]: 0.65 ~ 0.65 (174483046/2^28) [error = 0/1000000]
[With 32 bits]: 0.65 ~ 0.65 (2791728742/2^32) [error = 0/1000000] [With 32 bits]: 0.65 ~ 0.65 (2791728742/2^32) [error = 0/1000000]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 17857/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 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 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 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]
[With 20 bits]: 0.35 ~ 0.35 (734003/2^21) [error = 0/1000000] [With 20 bits]: 0.35 ~ 0.35 (734003/2^21) [error = 0/1000000]
[With 24 bits]: 0.35 ~ 0.35 (11744051/2^25) [error = 0/1000000] [With 24 bits]: 0.35 ~ 0.35 (11744051/2^25) [error = 0/1000000]
[With 28 bits]: 0.35 ~ 0.35 (187904819/2^29) [error = 0/1000000] [With 28 bits]: 0.35 ~ 0.35 (187904819/2^29) [error = 0/1000000]
[With 32 bits]: 0.35 ~ 0.35 (3006477107/2^33) [error = 0/1000000] [With 32 bits]: 0.35 ~ 0.35 (3006477107/2^33) [error = 0/1000000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000] [With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000] [With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000]
[With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 20 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 20 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 24 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 24 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 28 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 28 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 32 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000] [With 32 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md) [© Copyright](../COPYRIGHT.md)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment