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:
# [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 7](./4b-hands-on.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="#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:
### EXERCISE 16: transform struct `PowerOfTwoApprox` into a class
Make `PowerOfTwoApprox` into a class, with proper encapsulation:
* Both data attributes should be made private.
* Constant accessors will therefore be needed (non-constant ones should not be required here)
Expected output is the same as previously.
%% Cell type:markdown id: tags:
### EXERCISE 17: transform `Multiply()` into a method `Multiply()` of `PowerOfTwoApprox`
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.
%% Cell type:markdown id: tags:
### 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.
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 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:
%% 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
TestDisplayPowerOfTwoApprox test_display_approx;
for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx.Do(nbits);
std::cout << std::endl;
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;
}
```
%% Cell type:markdown id: tags:
Output will be ordered differently:
````
[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 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 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 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 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:
### 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.
* The two floating point values.
* Their integer coefficient.
New `main()` is:
%% 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
TestDisplayPowerOfTwoApprox test_display_approx;
for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx.Do(nbits);
std::cout << std::endl;
TestDisplayMultiply test_DisplayMultiply;
TestDisplaySumOfMultiply test_display_sum_of_multiply;
for (int nbits = 1; nbits <= 8; ++nbits)
test_DisplayMultiply.Do(nbits);
test_display_sum_of_multiply.Do(nbits);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
### 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.
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:
* 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).
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 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)).
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 };
````
To sum up, the signature or `PrintLine()` should be:
````
void PrintLine(int nbits, double exact, double approx, int maximum_error_index,
std::string optional_string1, std::string optional_string2,
RoundToInteger round_to_integer);
````
%% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md)
......
%% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 8](./7b-hands-on.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="#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:
### EXERCISE 21: base class `TestDisplay`
Create a base class `TestDisplay` from which both `TestDisplayPowerOfTwoApprox` and `TestDisplaySum` will inherit publicly.
This class:
* Should get a constructor which sets the resolution.
* 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.
%% Cell type:markdown id: tags:
### 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.
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.
The `main()` to use:
%% 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
TestDisplayPowerOfTwoApprox065 test_display_approx065(100);
for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx065.Do(nbits);
std::cout << std::endl;
TestDisplayPowerOfTwoApprox035 test_display_approx035(100);
for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx035.Do(nbits);
std::cout << std::endl;
TestDisplayMultiply test_DisplayMultiply(1000);
TestDisplaySumOfMultiply test_display_sum_of_multiply(1000);
for (int nbits = 1; nbits <= 8; ++nbits)
test_DisplayMultiply.Do(nbits);
test_display_sum_of_multiply.Do(nbits);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
_Expected output:_
````
[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:
### 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.
The declaration of the class should look like:
%% Cell type:code id: tags:
``` C++17
class TestDisplayContainer
{
public:
//! 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_
//! is incremented. If the end-user attempts to register more than three items, the Error() function is called.
void Register(TestDisplay* test_display);
//! 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;
private:
//! List of all known `TestDisplay` objects.
TestDisplay* list_[3];
//! Index to place the next register object. If '3', no more object may be registered.
int current_position_ {};
};
```
%% 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:
%% Cell type:code id: tags:
``` C++17
//! Function for error handling. We will see later how to fulfill the same functionality more properly.
[[noreturn]] void Error(std::string explanation)
{
std::cout << "ERROR: " << explanation << std::endl;
exit(EXIT_FAILURE);
}
```
%% Cell type:markdown id: tags:
The `main()` to use is:
%% 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
TestDisplayContainer container;
container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
container.Register(new TestDisplayMultiply(10000));
container.Register(new TestDisplaySumOfMultiply(10000));
container.Do(4, 16, 4);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
_Expected result:_
[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 = 299/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 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
%% Cell type:markdown id: tags:
### 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:
````
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).
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).
* 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`.
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`).
%% Cell type:markdown id: tags:
### 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).
Replace the `Do()` method by a free function with signature:
````
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`:
- 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:
````
const TestDisplay& GetElement(std::size_t i) const
````
(but others are also possible - you may prefer to return a pointer rather than a reference).
New `main()` is:
%% 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
TestDisplayContainer container(3);
container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
container.Register(new TestDisplayMultiply(10000));
container.Register(new TestDisplaySumOfMultiply(10000));
Loop(4, 16, 4, container);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md)
......
%% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Templates](./0-main.ipynb) - [Hands-on 12](./1b-hands-on.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="#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:
### Introduction
[This notebook](../HandsOn/HowTo.ipynb) explains very briefly your options to run the hands-ons.
%% Cell type:markdown id: tags:
### Context: when `int` is not enough
So far, we have not put much stress on our representation:
- We have always used positive values (spoiler: negative don't work...)
- 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).
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.
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).
%% Cell type:markdown id: tags:
### EXERCISE 31: make `PowerOfTwoApprox` a template class
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`.
Make sure to modify:
* The type of the data attribute.
* 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).
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):_
[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 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 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 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 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 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 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 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 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 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]
%% Cell type:markdown id: tags:
### EXERCISE 32: follow the thread...
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]
return TimesPowerOf2(approx.GetNumerator() * coefficient, -approx.GetExponent());
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
../exercise31.cpp:362:64: note: in instantiation of function template specialization 'operator*<long>' requested here
int approx = approximation1 * coefficient1 + coefficient2 * approximation2;
````
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.
* 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):
* `TimesPowerOf2()` should also be transformed into a template function. Therefore `MaxInt()` should as well.
* `RoundAsInt()` should also be modified
* 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.
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
````
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...
_Expected results (with `long`):_
[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 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 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 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 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 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 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 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 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 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]
%% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment