diff --git a/5-UsefulConceptsAndSTL/0-main.ipynb b/5-UsefulConceptsAndSTL/0-main.ipynb index f53ae77f83fdf1ba7be2224681b15bb00c609472..d333f780c6de232efc823e1f47305069fd672591 100644 --- a/5-UsefulConceptsAndSTL/0-main.ipynb +++ b/5-UsefulConceptsAndSTL/0-main.ipynb @@ -18,9 +18,8 @@ " * [TP 15](/notebooks/5-UsefulConceptsAndSTL/3b-TP.ipynb)\n", "* [Associative containers](/notebooks/5-UsefulConceptsAndSTL/4-AssociativeContainers.ipynb)\n", "* [Move semantics](/notebooks/5-UsefulConceptsAndSTL/5-MoveSemantics.ipynb)\n", - " * [TP 16](/notebooks/5-UsefulConceptsAndSTL/5b-TP.ipynb)\n", "* [Smart pointers](/notebooks/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb)\n", - " * [TP 17](/notebooks/5-UsefulConceptsAndSTL/6b-TP.ipynb)\n", + " * [TP 16](/notebooks/5-UsefulConceptsAndSTL/6b-TP.ipynb)\n", "* [Algorithms](/notebooks/5-UsefulConceptsAndSTL/7-Algorithms.ipynb)\n" ] }, diff --git a/6-InRealEnvironment/2b-TP.ipynb b/6-InRealEnvironment/2b-TP.ipynb index 3a49e3e908320072de70ea74383c761d5bb2ed5d..cf6a0285a89216ee4b8b5d3b08232a079869a9c4 100644 --- a/6-InRealEnvironment/2b-TP.ipynb +++ b/6-InRealEnvironment/2b-TP.ipynb @@ -14,7 +14,7 @@ }, "source": [ "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n", - "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span></li><li><span><a href=\"#EXERCICE-52\" data-toc-modified-id=\"EXERCICE-52-2\">EXERCICE 52</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=\"#EXERCICE-43\" data-toc-modified-id=\"EXERCICE-43-2\">EXERCICE 43</a></span></li></ul></div>" ] }, { @@ -32,19 +32,41 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### EXERCICE 52\n", + "### EXERCICE 43\n", "\n", "Reorganize the project in several files:\n", "\n", - "- Only `loop()` and `main()` functions should remain in exercice52.cpp\n", - "- Exceptions should be separated in two files `Exception.cpp` and `Exception.hpp`.\n", - "- `PowerOfTwoApprox` will be put in two files: `PowerOfTwoApprox.hpp` and `PowerOfTwoApprox.hxx`. The latter will be included at the end of the former. You should also place in the same files the free functions that work closely with this class (e.g. `operator<<`).\n", + "- Only `loop()` and `main()` functions should be put in _main.cpp_.\n", + "- `Error` should be declared in `Error.hpp` and defined in `Error.cpp`.\n", + "- Free functions such as `times_power_of_2` and `round_as_int` should be put in `Tools` files. As all these definitions are template, they should be in a header file (that might be the same as the one used for declaration, or a different one if you want to split declaration and definition - in this case don't forget to include it at the end of the hpp file!)\n", + "- Likewise for `PowerOfTwoApprox`. Closely related free functions (such as `operator<<`) should be put in the same file(s).\n", + "- You may put all `TestDIsplay` functionalities together. Beware: some definitions are template and must be in header files, whereas some aren't and should therefore be compiler.\n", "\n", - "**WARNING:** If you get complete template specializations, definition should be in a `cpp` file or inlined in header file!\n", - "- Do the same for the `TestDisplay` and its derived classes; you will need three files here (`cpp`, `hpp` and `hxx`).\n", - "- Finally, create two files `Tools.hpp` and `Tools.hxx` to put inside `times_power_of_2()`, `round_as_int` and `max_int`.\n", + "To do the exercice, create an _Exercice43_ directory in the TP root (and include it in your main CMakeLists.txt).\n", "\n", - "The provided CMake contains already the steps to make this work." + "Create the files in this directory, and use the following CMakeLists.txt:\n", + "\n", + "````\n", + "add_library(exercice43_lib\n", + " SHARED\n", + " # Header files are not strictly necessary but may be useful for some CMake generators.\n", + " ${CMAKE_CURRENT_LIST_DIR}/Error.cpp\n", + " ${CMAKE_CURRENT_LIST_DIR}/Error.hpp\n", + " ${CMAKE_CURRENT_LIST_DIR}/PowerOfTwoApprox.hpp\n", + " ${CMAKE_CURRENT_LIST_DIR}/PowerOfTwoApprox.hxx\n", + " ${CMAKE_CURRENT_LIST_DIR}/TestDisplay.cpp\n", + " ${CMAKE_CURRENT_LIST_DIR}/TestDisplay.hpp\n", + " ${CMAKE_CURRENT_LIST_DIR}/TestDisplay.hxx\n", + " ${CMAKE_CURRENT_LIST_DIR}/Tools.hpp\n", + " ${CMAKE_CURRENT_LIST_DIR}/Tools.hxx)\n", + "\n", + "\n", + "add_executable(exercice43\n", + " ${CMAKE_CURRENT_LIST_DIR}/main.cpp)\n", + " \n", + "target_link_libraries(exercice43 \n", + " exercice43_lib)\n", + "```` " ] }, { diff --git a/TP/6-InRealEnvironment/CMakeLists.txt b/TP/6-InRealEnvironment/CMakeLists.txt index 63404531a7deb3902a8d55cd41936ad6a6d4c2b6..974de60a02698d8c60e750a79672d9754427a075 100644 --- a/TP/6-InRealEnvironment/CMakeLists.txt +++ b/TP/6-InRealEnvironment/CMakeLists.txt @@ -1,47 +1,11 @@ cmake_minimum_required(VERSION 3.9) -# Add a compiler flag only if it is accepted. -# This macro is usually defined once and for all in a specific file which is included in the CMakeLists.txt in which -# you need it. -include(CheckCXXCompilerFlag) -macro(add_cxx_compiler_flag _flag) - string(REPLACE "-" "_" _flag_var ${_flag}) - check_cxx_compiler_flag("${_flag}" CXX_COMPILER_${_flag_var}_OK) +include(../../cmake/Settings.cmake) - if(CXX_COMPILER_${_flag_var}_OK) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}") - endif() -endmacro() - -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to 'Debug' as none was specified.") - set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" - "MinSizeRel" "RelWithDebInfo") -endif() - - - -set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ compiler") -set(CMAKE_C_COMPILER clang CACHE STRING "C compiler") -set(CMAKE_CXX_STANDARD 17 CACHE INTEGER "Version of the C++ standard to use") -set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "If ON the GNU version of the standard is used.") - -project(GettingStartedWithModernCpp_TP_Template) - - -add_cxx_compiler_flag("-Weverything") # all warnings for clang -add_cxx_compiler_flag("-Wall") # for gcc (and recognized by clang) -add_cxx_compiler_flag("-Wextra") # for gcc (and recognized by clang) -add_cxx_compiler_flag("-Wconversion")# for gcc -add_cxx_compiler_flag("-Wno-c++98-compat") # We assume we are using modern C++ -add_cxx_compiler_flag("-Wno-c++98-compat-pedantic") # We assume we are using modern C++ -add_cxx_compiler_flag("-Wno-padded") +project(GettingStartedWithModernCpp_TP_RealEnv) +include(../../cmake/AfterProjectSettings.cmake) add_executable(initial initial_file.cpp) -# add_library(exercice52_lib STATIC Exception.cpp TestDisplay.cpp) -# add_executable(exercice52 exercice52.cpp) -# target_link_libraries(exercice52 exercice52_lib) \ No newline at end of file +include(${CMAKE_CURRENT_LIST_DIR}/Exercice43/CMakeLists.txt) diff --git a/TP/6-InRealEnvironment/Solution/Exception.cpp b/TP/6-InRealEnvironment/Solution/Exception.cpp deleted file mode 100644 index cebc1ee194114fea318e1a81fab9f30cce619763..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/Exception.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Exception.hpp" - -Error::Error(std::string&& message) -: message_(message) -{ } - - -const char* Error::what() const noexcept -{ - return message_.c_str(); -} - - -Overflow::Overflow() -: Error("An overflow occurred!") -{ } - - -Overflow::~Overflow() = default; - diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/CMakeLists.txt b/TP/6-InRealEnvironment/Solution/Exercice43/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..df2fc32ae7be99605202ccb8621c9e8012c70d4e --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/CMakeLists.txt @@ -0,0 +1,20 @@ +add_library(exercice43_lib + SHARED + # Header files are not strictly necessary but may be useful for some CMake generators. + ${CMAKE_CURRENT_LIST_DIR}/Error.cpp + ${CMAKE_CURRENT_LIST_DIR}/Error.hpp + ${CMAKE_CURRENT_LIST_DIR}/PowerOfTwoApprox.hpp + ${CMAKE_CURRENT_LIST_DIR}/PowerOfTwoApprox.hxx + ${CMAKE_CURRENT_LIST_DIR}/TestDisplay.cpp + ${CMAKE_CURRENT_LIST_DIR}/TestDisplay.hpp + ${CMAKE_CURRENT_LIST_DIR}/TestDisplay.hxx + ${CMAKE_CURRENT_LIST_DIR}/Tools.hpp + ${CMAKE_CURRENT_LIST_DIR}/Tools.hxx) + + +add_executable(exercice43 + ${CMAKE_CURRENT_LIST_DIR}/main.cpp) + +target_link_libraries(exercice43 + exercice43_lib) + \ No newline at end of file diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/Error.cpp b/TP/6-InRealEnvironment/Solution/Exercice43/Error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1593d42bd57d8c85db6de76f9f4056982f76636 --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/Error.cpp @@ -0,0 +1,11 @@ +#include "Error.hpp" + +Error::Error(const std::string& message) +: message_(message) +{ } + + +const char* Error::what() const noexcept +{ + return message_.c_str(); +} diff --git a/TP/6-InRealEnvironment/Solution/Exception.hpp b/TP/6-InRealEnvironment/Solution/Exercice43/Error.hpp similarity index 55% rename from TP/6-InRealEnvironment/Solution/Exception.hpp rename to TP/6-InRealEnvironment/Solution/Exercice43/Error.hpp index c8f218437d60aa9c7381bf658b1213f831216a93..e1f804bab66caf8917887c2b15480b4138582653 100644 --- a/TP/6-InRealEnvironment/Solution/Exception.hpp +++ b/TP/6-InRealEnvironment/Solution/Exercice43/Error.hpp @@ -1,16 +1,15 @@ -#ifndef EXCEPTION_HPP -# define EXCEPTION_HPP +#ifndef EXCEPTIONS_HPP +#define EXCEPTIONS_HPP -#include <exception> #include <string> - +#include <exception> class Error : public std::exception { public: //! Constructor. - Error(std::string&& message); + Error(const std::string& message); //! Overrides what method. virtual const char* what() const noexcept override; @@ -21,18 +20,4 @@ private: }; - -class Overflow : public Error -{ -public: - - //! Constructor. - Overflow(); - - //! Destructor. - virtual ~Overflow(); - - -}; - #endif diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/PowerOfTwoApprox.hpp b/TP/6-InRealEnvironment/Solution/Exercice43/PowerOfTwoApprox.hpp new file mode 100644 index 0000000000000000000000000000000000000000..611be6c3e48e3ededeeb0edb9e402f79e539746f --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/PowerOfTwoApprox.hpp @@ -0,0 +1,74 @@ +#ifndef POWER_OF_TWO_APPROX_HPP +#define POWER_OF_TWO_APPROX_HPP + +#include <iostream> +#include <string> + +#include "Error.hpp" +#include "Tools.hpp" + + +//! Class to group the two integers used in the approximation we define. +template<class IntT> +class PowerOfTwoApprox +{ +public: + + //! Compute the best possible approximation of `value` with `Nbits` + PowerOfTwoApprox(int Nbits, double value); + + //! \return The approximation as a floating point. + explicit operator double() const; + + //! Accessor to numerator. + IntT GetNumerator() const; + + //! Accessor to exponent. + int GetExponent() const; + + //! Sign as a character: either '-' or ''. + // String might seem overkill, but empty char for positive case triggers a warnings. + std::string GetSignAsCharacter() const; + + //! Sign as a number (e.g. 1 or -1). + IntT GetSignAsNumber() const; + + +private: + + IntT numerator_ {}; + int exponent_ {}; + char sign_ { 1 }; +}; + + +template<class IntT> +std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<IntT>& approximation); + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +//! Note: could be put in the struct... but may be kept a free function as well! We will see much later +//! the anonymous namespace, in which I would typically put such a free function. +template<class IntT> +void helper_compute_power_of_2_approx(double value, int exponent, IntT& numerator, IntT& denominator); + + + +/*! + * \brief Multiply the approximate representation by an integer. + * + * \param[in] coefficient Integer coefficient by which the object is multiplied. + * + * \return An approximate integer result of the multiplication. + */ +template<class IntT> +IntT operator*(IntT coefficient, const PowerOfTwoApprox<IntT>& approx); + +template<class IntT> +IntT operator*(const PowerOfTwoApprox<IntT>& approx, IntT coefficient); + + +#include "PowerOfTwoApprox.hxx" + +#endif diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/PowerOfTwoApprox.hxx b/TP/6-InRealEnvironment/Solution/Exercice43/PowerOfTwoApprox.hxx new file mode 100644 index 0000000000000000000000000000000000000000..06dc0a5978f7bf6a2436b7498657e310e368dc76 --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/PowerOfTwoApprox.hxx @@ -0,0 +1,108 @@ + +template<class IntT> +void helper_compute_power_of_2_approx(double value, int exponent, IntT& numerator, IntT& denominator) +{ + constexpr IntT one = static_cast<IntT>(1); + denominator = times_power_of_2(one, exponent); + numerator = round_as_int<IntT>(value * denominator); +} + + +template<class IntT> +PowerOfTwoApprox<IntT>::PowerOfTwoApprox(int Nbits, double value) +{ + IntT max_numerator = max_int<IntT>(Nbits); + + auto& numerator = numerator_; + int& exponent = exponent_; + + numerator = 0; + exponent = 0; + IntT denominator {}; + + if (value < 0.) + { + sign_ = -1; + value = -value; + } + + do + { + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); + } + while (numerator <= max_numerator); + + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); +} + + +template<class IntT> +PowerOfTwoApprox<IntT>::operator double() const +{ + constexpr IntT one = static_cast<IntT>(1); + IntT denominator = times_power_of_2(one, exponent_); + return static_cast<double>(numerator_) * sign_ / denominator; +} + + +template<class IntT> +IntT PowerOfTwoApprox<IntT>::GetNumerator() const +{ + return numerator_; +} + + +template<class IntT> +int PowerOfTwoApprox<IntT>::GetExponent() const +{ + return exponent_; +} + + +template<class IntT> +std::string PowerOfTwoApprox<IntT>::GetSignAsCharacter() const +{ + assert(sign_ == 1 || sign_ == -1); + + if (sign_ == 1) + return ""; + else + return "-"; +} + + +template<class IntT> +IntT PowerOfTwoApprox<IntT>::GetSignAsNumber() const +{ + return static_cast<IntT>(sign_); +} + + + +template<class IntT> +std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<IntT>& approximation) +{ + out << approximation.GetSignAsCharacter() << PrintInt(approximation.GetNumerator()) << "/2^" << approximation.GetExponent(); + return out; +} + + +template<class IntT> +IntT operator*(IntT coefficient, const PowerOfTwoApprox<IntT>& approx) +{ + IntT product; + + if (__builtin_mul_overflow(approx.GetNumerator(), coefficient, &product)) + throw Error("Overflow! (in operator*(IntT, const PowerOfTwoApprox<IntT>&))"); + + return approx.GetSignAsNumber() * times_power_of_2(product, -approx.GetExponent()); +} + + +template<class IntT> +IntT operator*(const PowerOfTwoApprox<IntT>& approx, IntT coefficient) +{ + return coefficient * approx; +} diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.cpp b/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a532972921bf10a6f7ca5b48fa5f79cc6c8c170 --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.cpp @@ -0,0 +1,23 @@ +#include <iostream> +#include "TestDisplay.hpp" + + + +TestDisplay::TestDisplay(int resolution) +: resolution_(resolution) +{ } + + +TestDisplay::~TestDisplay() = default; + + +void TestDisplay::operator()(int Nbits) const +{ + static_cast<void>(Nbits); // neutralize warning about unused argument at no runtime cost. +} + +void TestDisplay::PrintOverflow(int Nbits, const Error& e) const +{ + std::cout << "[With " << Nbits << " bits]: " << e.what() << std::endl; +} + diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.hpp b/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f82b2eddf5af5692a227b7f626e89c85b24ac528 --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.hpp @@ -0,0 +1,135 @@ +#ifndef TEST_DISPLAY_HPP +#define TEST_DISPLAY_HPP + +#include <string> +#include <sstream> + +#include "PowerOfTwoApprox.hpp" +#include "Tools.hpp" + +class TestDisplay +{ +public: + + //! Constructor which sets the only the resolution (i.e. the maximum index upon which error is defined). + TestDisplay(int resolution); + + //! To make TestDisplay an abstract class. + virtual ~TestDisplay(); + + //! Pure virtual method Do(). + virtual void operator()(int Nbits) const = 0; + + +protected: + + /*! + * \brief Print a line with information about error. + * + * \param[in] optional_string1 String that might appear just after the "[With N bits]:". + * \param[in] optional_string2 String that might appear just before the "[error = ...]". + * \param[in] do_round_to_integer If yes, the exact result is approximated as an integer. + */ + template<class IntT> + void PrintLine(int Nbits, double exact, double approx, + std::string optional_string1 = "", std::string optional_string2 = "", + RoundToInteger do_round_to_integer = RoundToInteger::no) const; + + //! Function to call when an overflow occurred. + void PrintOverflow(int Nbits, const Error& e) const; + + +private: + + //! Resolution. + const int resolution_; + +}; + + + + +template<class IntT> +class TestDisplayPowerOfTwoApprox : public TestDisplay +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox(int resolution); + + //! Destructor + virtual ~TestDisplayPowerOfTwoApprox() override; + + //! Pure virtual method Do(). + virtual void operator()(int Nbits)const override = 0; + +protected: + + //! Method in charge of the actual display. + void Display(int Nbits, double value) const; + +}; + + + +template<class IntT> +class TestDisplayPowerOfTwoApproxMinus065 : public TestDisplayPowerOfTwoApprox<IntT> +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApproxMinus065(int resolution); + + //! Destructor, + ~TestDisplayPowerOfTwoApproxMinus065() override; + + //! Display the output for the chosen `Nbits`. + void operator()(int Nbits)const override; + +}; + + + +template<class IntT> +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox<IntT> +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Destructor, + ~TestDisplayPowerOfTwoApprox035() override; + + //! Display the output for the chosen `Nbits`. + void operator()(int Nbits)const override; + +}; + + + +template<class IntT> +class TestDisplayMultiply : public TestDisplay +{ +public: + + //! Constructor. + explicit TestDisplayMultiply(int resolution); + + //! To make the class a concrete one. + virtual ~TestDisplayMultiply() override; + + + //! Display the output for the chosen `Nbits`. + void operator()(int Nbits)const override; + +private: + + //! Method in charge of the actual display. + void Display(int Nbits, double value1, IntT coefficient1, double value2, IntT coefficient2) const; + +}; + +#include "TestDisplay.hxx" + +#endif diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.hxx b/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.hxx new file mode 100644 index 0000000000000000000000000000000000000000..2b0a67096463937ee5b2fde4da899b03340a6e4d --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/TestDisplay.hxx @@ -0,0 +1,133 @@ + + +template<class IntT> +void TestDisplay::PrintLine(int Nbits, double exact, double approx, + std::string optional_string1, std::string optional_string2, + RoundToInteger do_round_to_integer) const +{ + IntT error = round_as_int<IntT>(resolution_ * std::fabs(exact - approx) / std::fabs(exact)); + + std::cout << "[With " << Nbits << " bits]: " << optional_string1 + << (do_round_to_integer == RoundToInteger::yes ? round_as_int<IntT>(exact) : exact) << " ~ " << approx + << optional_string2 + << " [error = " << PrintInt(error) << "/" << resolution_ << "]" + << std::endl; +} + + + + +template<class IntT> +TestDisplayPowerOfTwoApprox<IntT>::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +template<class IntT> +TestDisplayPowerOfTwoApprox<IntT>::~TestDisplayPowerOfTwoApprox() = default; + + +template<class IntT> +void TestDisplayPowerOfTwoApprox<IntT>::Display(int Nbits, double value) const +{ + std::ostringstream oconv; + + try + { + PowerOfTwoApprox<IntT> approximation(Nbits, value); + + const double approx = static_cast<double>(approximation); + + oconv << " (" << approximation << ")"; + PrintLine<IntT>(Nbits, value, approx, "", oconv.str()); + } + catch(const Error& e) + { + PrintOverflow(Nbits, e); + } +} + + + + +template<class IntT> +TestDisplayPowerOfTwoApproxMinus065<IntT>::TestDisplayPowerOfTwoApproxMinus065(int resolution) +: TestDisplayPowerOfTwoApprox<IntT>(resolution) +{ } + + +template<class IntT> +TestDisplayPowerOfTwoApproxMinus065<IntT>::~TestDisplayPowerOfTwoApproxMinus065() = default; + + +template<class IntT> +void TestDisplayPowerOfTwoApproxMinus065<IntT>::operator()(int Nbits) const +{ + this->Display(Nbits, -0.65); +} + + + +template<class IntT> +TestDisplayPowerOfTwoApprox035<IntT>::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox<IntT>(resolution) +{ } + + +template<class IntT> +TestDisplayPowerOfTwoApprox035<IntT>::~TestDisplayPowerOfTwoApprox035() = default; + + +template<class IntT> +void TestDisplayPowerOfTwoApprox035<IntT>::operator()(int Nbits) const +{ + this->Display(Nbits, 0.35); +} + + +template<class IntT> +TestDisplayMultiply<IntT>::TestDisplayMultiply(int resolution) +: TestDisplay(resolution) +{ } + + +template<class IntT> +TestDisplayMultiply<IntT>::~TestDisplayMultiply() = default; + + +template<class IntT> +void TestDisplayMultiply<IntT>::operator()(int Nbits) const +{ + Display(Nbits, -0.65, static_cast<IntT>(3515), 0.35, static_cast<IntT>(4832)); +} + + +template<class IntT> +void TestDisplayMultiply<IntT>::Display(int Nbits, double value1, IntT coefficient1, double value2, IntT coefficient2) const +{ + try + { + double exact = value1 * coefficient1 + value2 * coefficient2; + + PowerOfTwoApprox<IntT> approximation1(Nbits, value1); + PowerOfTwoApprox<IntT> approximation2(Nbits, value2); + + IntT part1 = approximation1 * coefficient1; + IntT part2 = approximation2 * coefficient2; + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + IntT approx; + + if (__builtin_add_overflow(part1, part2, &approx)) + throw Error("Overflow (in TestDisplayMultiply<IntT>::Display())!"); + + PrintLine<IntT>(Nbits, exact, static_cast<double>(approx), oconv.str(), "", RoundToInteger::yes); + } + catch(const Error& e) + { + PrintOverflow(Nbits, e); + } +} + diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/Tools.hpp b/TP/6-InRealEnvironment/Solution/Exercice43/Tools.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f7aea5f3d616f5465c59efd201b1fefaf058e53 --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/Tools.hpp @@ -0,0 +1,61 @@ +#ifndef TOOLS_HPP +#define TOOLS_HPP + +#include <iostream> +#include <cmath> + +#include "Error.hpp" + + +//! I create here a new struct in charge of doing once and for all the conversion. +template<class IntT> +struct PrintIntHelper +{ + + //! std::conditional_t is really close to the ternary operator except that it applies to types. + using return_type = std::conditional_t + < + std::is_same<IntT, char>() || std::is_same<IntT, unsigned char>(), + int, + IntT + >; + + static return_type Do(IntT value); + + +}; + + + +enum class RoundToInteger { no, yes }; + + + + +// From C++ 14 onward +// The function wasn't mandatory per se but allows to a more user-friendly interface: +// PrintInt(value); +// rather than +// PrintIntHelper<IntT>::Do(value); +template<class T> +auto PrintInt(T value); + +//! Returns `number` * (2 ^ `exponent`) +template<class IntT> +IntT times_power_of_2(IntT number, int exponent); + + +//! Round to `x` the nearest integer. +template<class IntT> +IntT round_as_int(double x); + + +// Maximum integer that might be represented with `Nbits` bits. +template<class IntT> +IntT max_int(int Nbits); + + +#include "Tools.hxx" + +#endif + diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/Tools.hxx b/TP/6-InRealEnvironment/Solution/Exercice43/Tools.hxx new file mode 100644 index 0000000000000000000000000000000000000000..cddef9b066d62c7a6d4ba225e6b0baed0ff2b7ea --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/Tools.hxx @@ -0,0 +1,66 @@ +template<class IntT> +inline typename PrintIntHelper<IntT>::return_type PrintIntHelper<IntT>::Do(IntT value) +{ + return static_cast<return_type>(value); +}; + + +template<class T> +inline auto PrintInt(T value) +{ + return PrintIntHelper<T>::Do(value); +} + + +//! Returns `number` * (2 ^ `exponent`) +template<class IntT> +IntT times_power_of_2(IntT number, int exponent) +{ + constexpr IntT one = static_cast<IntT>(1); + constexpr IntT two = static_cast<IntT>(2); + + IntT sign = one; + + if (number < 0) + { + sign = -one; + number = -number; + }; + + + while (exponent > 0) + { + IntT product; + + if (__builtin_mul_overflow(number, two, &product)) + { + std::cout << "OVERFLOW for number " << number << std::endl; + throw Error("Overflow! (in times_power_of_2())"); + } + + number = product; + exponent -= 1; + } + while (exponent < 0) + { + number /= two; + exponent += 1 ; + } + + return one * number; +} + + +template<class IntT> +inline IntT round_as_int(double x) +{ + return static_cast<IntT>(std::round(x)); +} + + +template<class IntT> +inline IntT max_int(int Nbits) +{ + constexpr IntT one = static_cast<IntT>(1); + return (times_power_of_2(one, Nbits) - one); +} diff --git a/TP/6-InRealEnvironment/Solution/Exercice43/main.cpp b/TP/6-InRealEnvironment/Solution/Exercice43/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c966f3ccc51d304744b3daf038389ba2022cba43 --- /dev/null +++ b/TP/6-InRealEnvironment/Solution/Exercice43/main.cpp @@ -0,0 +1,55 @@ +#include <vector> +#include <memory> + +#include "Tools.hpp" +#include "PowerOfTwoApprox.hpp" +#include "TestDisplay.hpp" + + + + +//! For each container stored, loop oover all those bits and print the result on screen. +void loop(int initial_Nbit, int final_Nbit, int increment_Nbit, const std::vector<std::unique_ptr<TestDisplay>>& container) +{ + for (const auto& ptr : container) + { + assert(ptr != nullptr); + const auto& current_test_display = *ptr; + + for (int Nbits = initial_Nbit; Nbits <= final_Nbit; Nbits += increment_Nbit) + current_test_display(Nbits); + + std::cout << std::endl; + } +} + + +/************************************/ +// Main function +/************************************/ + +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 + + try + { + std::vector<std::unique_ptr<TestDisplay>> container; + + using integer_type = long; + + container.emplace_back(std::make_unique<TestDisplayPowerOfTwoApproxMinus065<integer_type>>(100000000)); + container.emplace_back(std::make_unique<TestDisplayPowerOfTwoApprox035<integer_type>>(100000000)); + container.emplace_back(std::make_unique<TestDisplayMultiply<integer_type>>(1000000)); + + loop(4, 32, 4, container); + } + catch(const std::exception& e) + { + std::cerr << "An error occurred in the program: " << e.what() << std::endl; + } + + return EXIT_SUCCESS; +} + diff --git a/TP/6-InRealEnvironment/Solution/PowerOfTwoApprox.hpp b/TP/6-InRealEnvironment/Solution/PowerOfTwoApprox.hpp deleted file mode 100644 index 4fb986b4815d8efefe086ec40ec37d582424b8c2..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/PowerOfTwoApprox.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef POWER_OF_TWO_APPROX_HPP -# define POWER_OF_TWO_APPROX_HPP - -# include <iostream> -# include "Tools.hpp" - - -/*! - * \brief Structure to group together numerator and exponent used to represent a floating-point. - * - * Representation is numerator / 2^exponent, where numerator is as large as a selected number of bits make possible. - */ -template<class IntT> -class PowerOfTwoApprox -{ -public: - - //! Constructor that compute the best possible approximation of `value` with `Nbits` - PowerOfTwoApprox(int Nbits, double value); - - //! Returns the double value computed from `numerator_` and `exponent_`. - explicit operator double() const; - - /*! - * \brief Multiply the approximate representation by an integer. - * - * \param[in] coefficient Integer coefficient by which the object is multiplied. - * - * \return An approximate integer result of the multiplication. - */ - template<class IntU> - friend IntU operator*(const PowerOfTwoApprox<IntU>& approx, IntU coefficient); - - template<class IntU> - friend IntU operator*(IntU coefficient, const PowerOfTwoApprox<IntU>& approx); - - //! Get the value of the numerator. - IntT Numerator() const; - - //! Get the value of the exponent. - int Exponent() const; - -private: - - //! Numerator. - IntT numerator_ = 0; - - //! Exponent applied to the 2 at the denominator. - int exponent_ = 0; -}; - - - - -namespace std -{ - - - template<class IntT> - std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<IntT>& approx); - - - template<> - std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<char>& approx); - - - template<> - std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<unsigned char>& approx); - - -} // namespace std - - -# include "PowerOfTwoApprox.hxx" -#endif diff --git a/TP/6-InRealEnvironment/Solution/PowerOfTwoApprox.hxx b/TP/6-InRealEnvironment/Solution/PowerOfTwoApprox.hxx deleted file mode 100644 index df43d957a9e33ec343077003349a5ba3797f99e8..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/PowerOfTwoApprox.hxx +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef POWER_OF_TWO_APPROX_HXX -# define POWER_OF_TWO_APPROX_HXX - -namespace std -{ - - - template<class IntT> - std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<IntT>& approx) - { - out << approx.Numerator() << "/2^" << approx.Exponent(); - return out; - } - - - template<> - inline std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<char>& approx) - { - out << static_cast<int>(approx.Numerator()) << "/2^" << approx.Exponent(); - return out; - } - - - template<> - inline std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox<unsigned char>& approx) - { - out << static_cast<int>(approx.Numerator()) << "/2^" << approx.Exponent(); - return out; - } - - -} // namespace std - - - -template<class IntT> -IntT operator*(const PowerOfTwoApprox<IntT>& approx, IntT coefficient) -{ - IntT product; - - if (__builtin_mul_overflow(approx.Numerator(), coefficient, &product) != 0) - throw Overflow(); - - IntT ret = static_cast<IntT>(times_power_of_2<IntT>(product, -approx.Exponent())); - - return ret; -} - - -template<class IntT> -IntT operator*(IntT coefficient, const PowerOfTwoApprox<IntT>& approx) -{ - return approx * coefficient; -} - - - -template<class IntT> -PowerOfTwoApprox<IntT>::PowerOfTwoApprox(int Nbits, double value) -{ - auto& numerator = numerator_; - auto& exponent = exponent_; - - numerator = exponent = 0; - IntT denominator {}; - - IntT max_numerator = max_int<IntT>(Nbits); - - IntT previous_numerator {}, previous_denominator {}; - - do - { - ++exponent; - denominator = times_power_of_2<IntT>(1, exponent); - - numerator = round_as_int<IntT>(value * denominator); - - if ((numerator < previous_numerator) || (denominator < previous_denominator)) - throw Overflow(); - - previous_numerator = numerator; - previous_denominator = denominator; - } - while (numerator <= max_numerator); - - --exponent; - denominator = times_power_of_2<IntT>(1, exponent); - numerator = round_as_int<IntT>(value * denominator); -} - - -template<class IntT> -PowerOfTwoApprox<IntT>::operator double() const -{ - int denominator = times_power_of_2<IntT>(1, exponent_); - - return static_cast<double>(numerator_) / denominator; -} - - -template<class IntT> -IntT PowerOfTwoApprox<IntT>::Numerator() const -{ - return numerator_; -} - - -template<class IntT> -int PowerOfTwoApprox<IntT>::Exponent() const -{ - return exponent_; -} - - -#endif diff --git a/TP/6-InRealEnvironment/Solution/TestDisplay.cpp b/TP/6-InRealEnvironment/Solution/TestDisplay.cpp deleted file mode 100644 index 7dfd59d98a341d18b3d6a0cf17369e7e5975fb83..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/TestDisplay.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "TestDisplay.hpp" -#include "PowerOfTwoApprox.hpp" - - -TestDisplay::TestDisplay(int resolution) -: resolution_(resolution) -{ } - - -TestDisplay::~TestDisplay() = default; - - -void TestDisplay::PrintNumericalError(int Nbits, double exact, double approx, - std::string&& after_bit_string, std::string&& before_error) const -{ - int error = round_as_int<int>(resolution_ * std::fabs(exact - approx) / exact); - - std::cout << "[With " << Nbits << " bits]: " << after_bit_string - << exact << " ~ " << approx - << before_error - << " [error = " << error << "/" << resolution_ << "]" - << std::endl; -} - - -void TestDisplay::PrintOverflow(int Nbits) const -{ - std::cout << "[With " << Nbits << " bits]: Overflow! " << std::endl; -} diff --git a/TP/6-InRealEnvironment/Solution/TestDisplay.hpp b/TP/6-InRealEnvironment/Solution/TestDisplay.hpp deleted file mode 100644 index 2ccb00ea2bfb3d97e06a737a26d53a6339bfad8d..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/TestDisplay.hpp +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef TEST_DISPLAY_HPP -# define TEST_DISPLAY_HPP - -#include <string> -#include <sstream> -#include "PowerOfTwoApprox.hpp" - - -/*! - * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. - */ -class TestDisplay -{ -public: - - //! Constructor. - TestDisplay(int resolution); - - //! Virtual method. - virtual void operator()(int Nbits) const = 0; - - //! Virtual destructor. - virtual ~TestDisplay(); - -protected: - - /*! - * \brief Print a line with information about error. - * - * \param[in] after_bit_string String that might appear - */ - void PrintNumericalError(int Nbits, double exact, double approx, - std::string&& after_bit_string, std::string&& before_error) const; - - /*! - * \brief Print the line when an overflow occurred. - */ - void PrintOverflow(int Nbits) const; - - -private: - - //! Maximum error index. - const int resolution_; - -}; - - - -/*! - * \brief Class in charge of displaying the approximation for PowerOfTwoApprox for a value which is expected - * to be provided in a derived class. - */ -template<class IntT> -class TestDisplayPowerOfTwoApprox : public TestDisplay -{ -public: - - //! Constructor. - TestDisplayPowerOfTwoApprox(int resolution); - - //! Virtual destructor. - virtual ~TestDisplayPowerOfTwoApprox(); - -protected: - - //! Print the output for `value` when `Nbits` are available. - void Display(int Nbits, double value) const; - -}; - - -//! Run TestDisplayPowerOfTwoApprox for value 0.65 -template<class IntT> -class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox<IntT> -{ -public: - - //! Convenient alias. - using parent = TestDisplayPowerOfTwoApprox<IntT>; - - //! Constructor. - TestDisplayPowerOfTwoApprox065(int resolution); - - //! Print the output for the values 0.65 and 0.35. - void operator()(int Nbits) const override; - -}; - - -//! Run TestDisplayPowerOfTwoApprox for value 0.35 -template<class IntT> -class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox<IntT> -{ -public: - - //! Convenient alias. - using parent = TestDisplayPowerOfTwoApprox<IntT>; - - - //! Constructor. - TestDisplayPowerOfTwoApprox035(int resolution); - - //! Print the output for the values 0.65 and 0.35. - void operator()(int Nbits) const override; - -}; - - - -/*! - * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. - - */ -template<class IntT> -class TestDisplaySum : public TestDisplay -{ -public: - - //! Constructor. - TestDisplaySum(int resolution); - - - //! Print the output for the values 0.65 and 0.35. - void operator()(int Nbits) const override; - -private: - - //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. - void Display(int Nbits, double value1, IntT coefficient1, double value2, IntT coefficient2) const; - -}; - -# include "TestDisplay.hxx" -#endif diff --git a/TP/6-InRealEnvironment/Solution/TestDisplay.hxx b/TP/6-InRealEnvironment/Solution/TestDisplay.hxx deleted file mode 100644 index 8802a8d023294dc4677d0128dacc4ef2ee9e4683..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/TestDisplay.hxx +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef TEST_DISPLAY_HXX -# define TEST_DISPLAY_HXX - - - -template<class IntT> -TestDisplayPowerOfTwoApprox<IntT>::TestDisplayPowerOfTwoApprox(int resolution) -: TestDisplay(resolution) -{ } - - -template<class IntT> -TestDisplayPowerOfTwoApprox<IntT>::~TestDisplayPowerOfTwoApprox() = default; - - -template<class IntT> -void TestDisplayPowerOfTwoApprox<IntT>::Display(int Nbits, double value) const -{ - try - { - PowerOfTwoApprox<IntT> approx(Nbits, value); - - double double_approx = static_cast<double>(approx); - - std::ostringstream oconv; - oconv << " (" << approx << ')'; - - PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); - } - catch(const Overflow& ) - { - PrintOverflow(Nbits); - } -} - - -template<class IntT> -TestDisplayPowerOfTwoApprox065<IntT>::TestDisplayPowerOfTwoApprox065(int resolution) -: parent(resolution) -{ } - - -template<class IntT> -TestDisplayPowerOfTwoApprox035<IntT>::TestDisplayPowerOfTwoApprox035(int resolution) -: parent(resolution) -{ } - - -template<class IntT> -void TestDisplayPowerOfTwoApprox065<IntT>::operator()(int Nbits) const -{ - parent::Display(Nbits, 0.65); -} - - -template<class IntT> -void TestDisplayPowerOfTwoApprox035<IntT>::operator()(int Nbits) const -{ - parent::Display(Nbits, 0.35); -} - - - -/*==================================*/ -// TestDisplaySum -/*==================================*/ - -template<class IntT> -TestDisplaySum<IntT>::TestDisplaySum(int resolution) -: TestDisplay(resolution) -{ } - - -template<class IntT> -void TestDisplaySum<IntT>::operator()(int Nbits) const -{ - Display(Nbits, 0.65, 3515, 0.35, 4832); -} - - -template<class IntT> -void TestDisplaySum<IntT>::Display(int Nbits, double value1, IntT coefficient1, double value2, IntT coefficient2) const -{ - try - { - double exact = std::round(value1 * coefficient1 + value2 * coefficient2); - - PowerOfTwoApprox<IntT> approx1(Nbits, value1); - PowerOfTwoApprox<IntT> approx2(Nbits, value2); - - IntT product1 = coefficient1 * approx1; - IntT product2 = coefficient2 * approx2; - - IntT approx; - - // Not standard: for gcc and clang only! - // See https://stackoverflow.com/questions/199333/how-to-detect-unsigned-integer-multiply-overflow - if (__builtin_add_overflow(product1, product2, &approx) != 0) - throw Overflow(); - - std::ostringstream oconv; - oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; - - PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); - } - catch(const Overflow& ) - { - PrintOverflow(Nbits); - } -} -#endif diff --git a/TP/6-InRealEnvironment/Solution/Tools.hpp b/TP/6-InRealEnvironment/Solution/Tools.hpp deleted file mode 100644 index bc574495bcb6d20008fd51f6928b32a0290e011e..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/Tools.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TOOLS_HPP -# define TOOLS_HPP - -# include <cmath> -# include "Exception.hpp" - - -//! Returns `number` * (2 ^ `exponent`) -template<class IntT> -IntT times_power_of_2(IntT number, int exponent); - - -//! Round to `x` the nearest integer. -template<class IntT> -IntT round_as_int(double x); - - -//! Maximum integer that might be represented with `Nbits` bits. -template<class IntT> -IntT max_int(int Nbits); - -# include "Tools.hxx" - -#endif diff --git a/TP/6-InRealEnvironment/Solution/Tools.hxx b/TP/6-InRealEnvironment/Solution/Tools.hxx deleted file mode 100644 index a536758e0be1739e912fddac1e2607cdadf28bf2..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/Tools.hxx +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef TOOLS_HXX -# define TOOLS_HXX - -template<class IntT> -IntT times_power_of_2(IntT number, int exponent) -{ - constexpr IntT half_max = std::numeric_limits<IntT>::max() / 2; - - while (exponent > 0) - { - if (number > half_max) - throw Overflow(); - - number *= 2; - exponent -= 1; - } - - while (exponent < 0) - { - number /= 2; - exponent += 1; - } - - return number; -} - - -template<class IntT> -IntT round_as_int(double x) -{ - return static_cast<IntT>(std::round(x)); -} - - -template<class IntT> -IntT max_int(int Nbits) -{ - // static_cast for the sake of `short` case: short + short -> int! - return static_cast<IntT>(times_power_of_2<IntT>(1, Nbits) - 1); -} - - -#endif diff --git a/TP/6-InRealEnvironment/Solution/exercice52.cpp b/TP/6-InRealEnvironment/Solution/exercice52.cpp deleted file mode 100644 index a7c072c7f0af045c97fc7598cfc88ae29155b6e4..0000000000000000000000000000000000000000 --- a/TP/6-InRealEnvironment/Solution/exercice52.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include <vector> -#include <memory> - -#include "Exception.hpp" -#include "PowerOfTwoApprox.hpp" -#include "TestDisplay.hpp" - - - -//! Loop over the content of the container with `TestDisplay` objects. -//! NOTE: Didn't want to finish TP on this, but after reading (/notebooks/6-InRealEnvironment/5-Namespace.ipynb) this loop function should be put inside an unnamed namespace. -void loop(int Nbits_min, int Nbits_max, int Nbits_increment, std::vector<std::unique_ptr<TestDisplay>>& container); - - -/************************************/ -// Main function -/************************************/ - -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 - - try - { - { - std::vector<std::unique_ptr<TestDisplay>> container; - container.emplace_back(std::make_unique<TestDisplayPowerOfTwoApprox065<int>>(1000000)); - container.emplace_back(std::make_unique<TestDisplayPowerOfTwoApprox035<int>>(1000000)); - container.emplace_back(std::make_unique<TestDisplaySum<int>>(1000000)); - container.emplace_back(std::make_unique<TestDisplaySum<short>>(1000000)); - - loop(4, 16, 4, container); - } - - { - std::vector<std::unique_ptr<TestDisplay>> container; - container.emplace_back(std::make_unique<TestDisplayPowerOfTwoApprox065<char>>(1000)); - container.emplace_back(std::make_unique<TestDisplayPowerOfTwoApprox065<unsigned char>>(1000)); - loop(1, 8, 1, container); - } - } - catch(const std::exception& e) - { - std::cerr << "An error occurred in the program: " << e.what() << std::endl; - } - - return EXIT_SUCCESS; -} - - - -void loop(int Nbits_min, int Nbits_max, int Nbits_increment, std::vector<std::unique_ptr<TestDisplay>>& container) -{ - for (decltype(auto) test_display_ptr : container) - { - assert(test_display_ptr != nullptr); - decltype(auto) test_display = *test_display_ptr; - - for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) - test_display(Nbits); - - std::cout << std::endl; - } -} - diff --git a/TP/6-InRealEnvironment/initial_file.cpp b/TP/6-InRealEnvironment/initial_file.cpp index fd0a266fdc63e13b8a2760f5c5f3832b31c59b18..03d410dfd04a717b20f5d8a6cd56826f94480995 120000 --- a/TP/6-InRealEnvironment/initial_file.cpp +++ b/TP/6-InRealEnvironment/initial_file.cpp @@ -1 +1 @@ -../5-UsefulConceptsAndSTL/Solution/exercice51.cpp \ No newline at end of file +../5-UsefulConceptsAndSTL/Solution/exercice42.cpp \ No newline at end of file