diff --git a/1-ProceduralProgramming/TP/CMakeLists.txt b/1-ProceduralProgramming/TP/CMakeLists.txt index 29de5a59da9bd78de98f3d59dedcc9860da219b0..61032827c8cb94097f5720e7ebeb9061a80e5a06 100644 --- a/1-ProceduralProgramming/TP/CMakeLists.txt +++ b/1-ProceduralProgramming/TP/CMakeLists.txt @@ -14,11 +14,10 @@ macro(add_cxx_compiler_flag _flag) endmacro() -# Don't do such hardcoding in a real project: you want to be able to supersede these settings on command line. -set(CMAKE_CXX_COMPILER clang++ ) -set(CMAKE_C_COMPILER clang) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_EXTENSIONS OFF) +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_Procedural) diff --git a/2-ObjectProgramming/TP/CMakeLists.txt b/2-ObjectProgramming/TP/CMakeLists.txt index 3962844d5f0b91d51cc0913b0ff2810f8d5a0d52..6c1342580e070b2157149c924199c2bd547daad1 100644 --- a/2-ObjectProgramming/TP/CMakeLists.txt +++ b/2-ObjectProgramming/TP/CMakeLists.txt @@ -14,11 +14,10 @@ macro(add_cxx_compiler_flag _flag) endmacro() -# Don't do such hardcoding in a real project: you want to be able to supersede these settings on command line. -set(CMAKE_CXX_COMPILER clang++ ) -set(CMAKE_C_COMPILER clang) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_EXTENSIONS OFF) +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_Object) diff --git a/2-ObjectProgramming/TP/Solution/exercice24.cpp b/2-ObjectProgramming/TP/Solution/exercice24.cpp index fab403eef6be6dd2f2783a0e3ea91424d03f5310..9e33ffd501ddf4722df440b5978fa8861086290f 100644 --- a/2-ObjectProgramming/TP/Solution/exercice24.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice24.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/2-ObjectProgramming/TP/Solution/exercice25.cpp b/2-ObjectProgramming/TP/Solution/exercice25.cpp index e04b269a239f2cb1771492238b72003a37c910c5..78308d7ceadd13b9e65cb6d39130d97ee347d918 100644 --- a/2-ObjectProgramming/TP/Solution/exercice25.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice25.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/2-ObjectProgramming/TP/Solution/exercice26.cpp b/2-ObjectProgramming/TP/Solution/exercice26.cpp index ea7858d90b777a1554bd1b643b244d938080c4a2..d58bdeb26184c783d7888b581eaa2098edcee788 100644 --- a/2-ObjectProgramming/TP/Solution/exercice26.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice26.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/2-ObjectProgramming/TP/Solution/exercice27.cpp b/2-ObjectProgramming/TP/Solution/exercice27.cpp index e14f6495545124f7979d8bfc3cd511900ab751ca..2e89cd2d3b4f9b421db2be7754c2b3c1a59e268e 100644 --- a/2-ObjectProgramming/TP/Solution/exercice27.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice27.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/2-ObjectProgramming/TP/Solution/exercice28.cpp b/2-ObjectProgramming/TP/Solution/exercice28.cpp index a2fa985bd074109ecaa3c019e213482e7129912f..c0dcd446b0da3ace543e138b3e5d688e63df2dd9 100644 --- a/2-ObjectProgramming/TP/Solution/exercice28.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice28.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/2-ObjectProgramming/TP/Solution/exercice29.cpp b/2-ObjectProgramming/TP/Solution/exercice29.cpp index d3054e49b7977a348bced89883b00601d7b874ec..b52412b2acd83ca7b6579204277717e47fe0d5c6 100644 --- a/2-ObjectProgramming/TP/Solution/exercice29.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice29.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/2-ObjectProgramming/TP/Solution/exercice30.cpp b/2-ObjectProgramming/TP/Solution/exercice30.cpp index c539ed02067ecb88d4c4fc58576f9279a641c3ce..3a96d0c5e40739099139e2305b6039d2db2f7d8e 100644 --- a/2-ObjectProgramming/TP/Solution/exercice30.cpp +++ b/2-ObjectProgramming/TP/Solution/exercice30.cpp @@ -148,7 +148,7 @@ public: //! Print the output for the values 0.65 and 0.35. - void Do(int Nbits) const; + void Do(int Nbits) const override; private: diff --git a/3-Operators/0-main.ipynb b/3-Operators/0-main.ipynb index bee3a00c8ff134f0080d4123838d014906b8eb74..7c51344ad4480c281e0b9bbb6b48f06c2af6d70f 100644 --- a/3-Operators/0-main.ipynb +++ b/3-Operators/0-main.ipynb @@ -12,10 +12,13 @@ "metadata": {}, "source": [ "* [Introduction to the concept of operator overload](/notebooks/3-Operators/1-Intro.ipynb)\n", + " * [TP 8](/notebooks/3-Operators/1b-TP.ipynb)\n", "* [Comparison operators](/notebooks/3-Operators/2-Comparison.ipynb)\n", "* [Stream operators](/notebooks/3-Operators/3-Stream.ipynb)\n", + " * [TP 9](/notebooks/3-Operators/3b-TP.ipynb)\n", "* [Affectation operator and the canonical form of a class](/notebooks/3-Operators/4-CanonicalForm.ipynb)\n", - "* [Functors](/notebooks/3-Operators/5-Functors.ipynb)" + "* [Functors](/notebooks/3-Operators/5-Functors.ipynb)\n", + " * [TP 10](/notebooks/3-Operators/5b-TP.ipynb)" ] }, { diff --git a/3-Operators/1-Intro.ipynb b/3-Operators/1-Intro.ipynb index 98dd11a4343556f91c76bfa7356d86913d0b6a2c..1fd929031d40c9753343b5bead74ad52104700ee 100644 --- a/3-Operators/1-Intro.ipynb +++ b/3-Operators/1-Intro.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=\"#Motivation\" data-toc-modified-id=\"Motivation-1\">Motivation</a></span></li><li><span><a href=\"#Overloading-an-operator\" data-toc-modified-id=\"Overloading-an-operator-2\">Overloading an operator</a></span></li><li><span><a href=\"#Limitations\" data-toc-modified-id=\"Limitations-3\">Limitations</a></span></li><li><span><a href=\"#Conversion-operators\" data-toc-modified-id=\"Conversion-operators-4\">Conversion operators</a></span></li></ul></div>" + "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Motivation\" data-toc-modified-id=\"Motivation-1\">Motivation</a></span></li><li><span><a href=\"#Overloading-an-operator\" data-toc-modified-id=\"Overloading-an-operator-2\">Overloading an operator</a></span></li><li><span><a href=\"#Operator-between-different-types\" data-toc-modified-id=\"Operator-between-different-types-3\">Operator between different types</a></span></li><li><span><a href=\"#Limitations\" data-toc-modified-id=\"Limitations-4\">Limitations</a></span></li><li><span><a href=\"#Conversion-operators\" data-toc-modified-id=\"Conversion-operators-5\">Conversion operators</a></span></li></ul></div>" ] }, { @@ -311,6 +311,259 @@ "}" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Operator between different types\n", + "\n", + "It is also possible to define an operator which acts upon two objects of different nature:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class Vector4\n", + "{\n", + " public :\n", + "\n", + " Vector4(double x, double y, double z);\n", + " \n", + " Vector4() = default;\n", + " \n", + " void Print() const;\n", + " \n", + " Vector4 operator+(double value) const\n", + " {\n", + " Vector4 ret;\n", + " ret.x_ = x_ + value;\n", + " ret.y_ = y_ + value;\n", + " ret.z_ = z_ + value;\n", + " \n", + " return ret;\n", + " }\n", + "\n", + " private :\n", + " \n", + " double x_ = 0.;\n", + " double y_ = 0.;\n", + " double z_ = 0.;\n", + "}; " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "#include <iostream>\n", + "\n", + "void Vector4::Print() const\n", + "{\n", + " std::cout << \"(\" << x_ << \", \" << y_ << \", \" << z_ << \")\" << std::endl;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[1minput_line_12:1:10: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1mredefinition of 'Vector4'\u001b[0m\n", + "Vector4::Vector4(double x, double y, double z)\n", + "\u001b[0;1;32m ^\n", + "\u001b[0m\u001b[1minput_line_9:1:10: \u001b[0m\u001b[0;1;30mnote: \u001b[0mprevious definition is here\u001b[0m\n", + "Vector4::Vector4(double x, double y, double z)\n", + "\u001b[0;1;32m ^\n", + "\u001b[0m" + ] + }, + { + "ename": "Interpreter Error", + "evalue": "", + "output_type": "error", + "traceback": [ + "Interpreter Error: " + ] + } + ], + "source": [ + "Vector4::Vector4(double x, double y, double z)\n", + ": x_(x),\n", + "y_(y),\n", + "z_(z)\n", + "{ }" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(10, 8.2, 4)\n" + ] + } + ], + "source": [ + "{\n", + " Vector4 vector(5., 3.2, -1.);\n", + " Vector4 vector_plus_5 = vector + 5.;\n", + " vector_plus_5.Print();\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, pay attention to the fact this operator is not commutative: when you call \n", + "\n", + "````\n", + "Vector4 vector_plus_5 = vector + 5.;\n", + "````\n", + "\n", + "it is indeed a shortcut to\n", + "\n", + "````\n", + "Vector4 vector_plus_5 = vector.operator*(5.);\n", + "````\n", + "\n", + "and the following won't compile:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[1minput_line_14:4:32: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1minvalid operands to binary expression ('double' and 'Vector4')\u001b[0m\n", + " Vector4 vector_plus_5 = 5. + vector; // COMPILATION ERROR!\n", + "\u001b[0;1;32m ~~ ^ ~~~~~~\n", + "\u001b[0m" + ] + }, + { + "ename": "Interpreter Error", + "evalue": "", + "output_type": "error", + "traceback": [ + "Interpreter Error: " + ] + } + ], + "source": [ + "{\n", + " Vector4 vector(5., 3.2, -1.);\n", + " Vector4 vector_plus_5 = 5. + vector; // COMPILATION ERROR!\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want it to be possible, you have to define the operator with arguments in both orders; you therefore need to use out-of-class prototype of the function (can't show it currently due to Xeus-cling limitation).\n", + "\n", + "Of course, if you do so you should define one in way of the other:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "// Won't compile in Xeus-cling\n", + "\n", + "#include <cstdlib>\n", + "#include <iostream>\n", + "\n", + "class Vector5\n", + "{\n", + " public :\n", + "\n", + " Vector5(double x, double y, double z);\n", + " \n", + " Vector5() = default;\n", + " \n", + " void Print() const;\n", + " \n", + " friend Vector5 operator+(const Vector5& v, double value);\n", + " \n", + " friend Vector5 operator+(double value, const Vector5& v);\n", + "\n", + " private :\n", + " \n", + " double x_ = 0.;\n", + " double y_ = 0.;\n", + " double z_ = 0.;\n", + "}; \n", + "\n", + "\n", + "\n", + "void Vector5::Print() const\n", + "{\n", + " std::cout << \"(\" << x_ << \", \" << y_ << \", \" << z_ << \")\" << std::endl;\n", + "}\n", + "\n", + "\n", + "Vector5::Vector5(double x, double y, double z)\n", + ": x_(x),\n", + "y_(y),\n", + "z_(z)\n", + "{ }\n", + "\n", + "\n", + "\n", + "Vector5 operator+(const Vector5& v, double value)\n", + "{\n", + " Vector5 ret;\n", + " \n", + " ret.x_ = v.x_ + value;\n", + " ret.y_ = v.y_ + value;\n", + " ret.z_ = v.z_ + value;\n", + " \n", + " return ret;\n", + "}\n", + "\n", + "\n", + "Vector5 operator+(double value, const Vector5& v)\n", + "{\n", + " return v + value;\n", + "}\n", + "\n", + "\n", + "int main(int argc, char** argv)\n", + "{\n", + " Vector5 vector(5., 3.2, -1.);\n", + " Vector5 vector_plus_5 = vector + 5.;\n", + " Vector5 vector_plus_5_commutated = 5. + vector;\n", + " \n", + " vector_plus_5.Print();\n", + " vector_plus_5_commutated.Print();\n", + " \n", + " return EXIT_SUCCESS;\n", + "}\n" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/3-Operators/1b-TP.ipynb b/3-Operators/1b-TP.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..95c598d8fe698391ed3a82c7eca3014127bbe6ca --- /dev/null +++ b/3-Operators/1b-TP.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# [Getting started in C++](/) - [Operators](/notebooks/3-Operators/0-main.ipynb) - [TP 8](/notebooks/3-Operators/1b-TP.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "toc": true + }, + "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-31:-replace-PowerOfTwoApprox::DoubleValue-by-an-operator-double\" data-toc-modified-id=\"EXERCICE-31:-replace-PowerOfTwoApprox::DoubleValue-by-an-operator-double-2\">EXERCICE 31: replace <code>PowerOfTwoApprox::DoubleValue</code> by an <code>operator double</code></a></span></li><li><span><a href=\"#EXERCICE-32:-replace-PowerOfTwoApprox::Multiply-by-operator-*\" data-toc-modified-id=\"EXERCICE-32:-replace-PowerOfTwoApprox::Multiply-by-operator-*-3\">EXERCICE 32: replace <code>PowerOfTwoApprox::Multiply</code> by <code>operator *</code></a></span></li><li><span><a href=\"#EXERCICE-33:-commutativity\" data-toc-modified-id=\"EXERCICE-33:-commutativity-4\">EXERCICE 33: commutativity</a></span></li><li><span><a href=\"#EXERCICE-34:-operator[]\" data-toc-modified-id=\"EXERCICE-34:-operator[]-5\">EXERCICE 34: <code>operator[]</code></a></span></li></ul></div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Introduction\n", + "\n", + "[This notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.\n", + "\n", + "We will start from the solution to exercice 30 of the procedural object TP. `initial_file.cpp` in the TP directory is a copy to the solution of this exercice (symbolic link wouldn't have worked with Docker)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 31: replace `PowerOfTwoApprox::DoubleValue` by an `operator double`\n", + "\n", + "The arguments should remain the same." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 32: replace `PowerOfTwoApprox::Multiply` by `operator *`\n", + "\n", + "Arguments remain unchanged." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 33: commutativity\n", + "\n", + "In `TestDisplaySum::Display()`, you should have the line\n", + "\n", + "````\n", + "int approx = approx1 * coefficient1 + approx2 * coefficient2;\n", + "````\n", + "\n", + "Try the following one instead:\n", + "\n", + "````\n", + "int approx = coefficient1 * approx1 + coefficient2 * approx2;\n", + "````\n", + "\n", + "You should get at least a warning doing so... (at least with the CMake build I provide that activates `-Wconversion` warning - more on that [later](/notebooks/6-InRealEnvironment/3-Compilers.ipynb)...)\n", + "\n", + "Add a print line in `operator*`.\n", + "\n", + "Do you understand what happens? \n", + "\n", + "[Solution](/notebooks/3-Operators/1c-SolutionExercice33.ipynb)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 34: `operator[]`\n", + "\n", + "In `TestDisplayContainer`, replace `GetElement()` method by `operator[]`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "© _CNRS 2016_ - _Inria 2018_ \n", + "_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n", + "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "C++17", + "language": "C++17", + "name": "xeus-cling-cpp17" + }, + "language_info": { + "codemirror_mode": "text/x-c++src", + "file_extension": ".cpp", + "mimetype": "text/x-c++src", + "name": "c++", + "version": "-std=c++17" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of contents", + "title_sidebar": "Contents", + "toc_cell": true, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/3-Operators/1c-SolutionExercice33.ipynb b/3-Operators/1c-SolutionExercice33.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..d1c51a0a63e4144b2e6273f381d1c27720684544 --- /dev/null +++ b/3-Operators/1c-SolutionExercice33.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# [Getting started in C++](/) - [Operators](/notebooks/3-Operators/0-main.ipynb) - [TP 8 - Solution](/notebooks/3-Operators/1b-TP.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "toc": true + }, + "source": [ + "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n", + "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-33:-commutativity\" data-toc-modified-id=\"EXERCICE-33:-commutativity-1\">EXERCICE 33: commutativity</a></span></li></ul></div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 33: commutativity\n", + "\n", + "What happens in fact is that `operator*` is not commutative: it expects as first argument an object and as second argument an integer.\n", + "\n", + "So why does it work nonetheless?\n", + "\n", + "`operator*(int, PowerOfTwoApprox)` is not defined... but addition between an integer and a double is obviously possible, AND you've just defined before an implicit conversion to `double`.\n", + "\n", + "You should of course heed the warning and fix your code:\n", + "\n", + "* Make `operator double` explicit. Except in very specific cases, I advise you to always make such conversion operators explicit to avoid unintended side effects as the one we've just got.\n", + "* If commutativity is important for you, make `operator*` a friend function instead of a method and provide both ordering of arguments. \n", + "\n", + "The solution file implements both these modifications." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "© _CNRS 2016_ - _Inria 2018_ \n", + "_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n", + "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "C++17", + "language": "C++17", + "name": "xeus-cling-cpp17" + }, + "language_info": { + "codemirror_mode": "text/x-c++src", + "file_extension": ".cpp", + "mimetype": "text/x-c++src", + "name": "c++", + "version": "-std=c++17" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of contents", + "title_sidebar": "Contents", + "toc_cell": true, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/3-Operators/3b-TP.ipynb b/3-Operators/3b-TP.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..31ad741d05ae7ee5b2b154234bc0a2fee17d5de7 --- /dev/null +++ b/3-Operators/3b-TP.ipynb @@ -0,0 +1,88 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# [Getting started in C++](/) - [Operators](/notebooks/3-Operators/0-main.ipynb) - [TP 9](/notebooks/3-Operators/3b-TP.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "toc": true + }, + "source": [ + "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n", + "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-35:-operator<<\" data-toc-modified-id=\"EXERCICE-35:-operator<<-1\">EXERCICE 35: <code>operator<<</code></a></span></li></ul></div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 35: `operator<<`\n", + "\n", + "Introduce an `operator<<` for class `PowerOfTwoApprox` which provides the numerator and exponent used, e.g. `10/2^4`.\n", + "\n", + "Use it in `TestDisplayPowerOfTwoApprox::Display()`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "© _CNRS 2016_ - _Inria 2018_ \n", + "_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n", + "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "C++17", + "language": "C++17", + "name": "xeus-cling-cpp17" + }, + "language_info": { + "codemirror_mode": "text/x-c++src", + "file_extension": ".cpp", + "mimetype": "text/x-c++src", + "name": "c++", + "version": "-std=c++17" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of contents", + "title_sidebar": "Contents", + "toc_cell": true, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/3-Operators/5b-TP.ipynb b/3-Operators/5b-TP.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..56bc68bd6e41827b8d1c4600fd376e824dab879c --- /dev/null +++ b/3-Operators/5b-TP.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# [Getting started in C++](/) - [Operators](/notebooks/3-Operators/0-main.ipynb) - [TP 10](/notebooks/3-Operators/5b-TP.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "toc": true + }, + "source": [ + "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n", + "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-36:-functor\" data-toc-modified-id=\"EXERCICE-36:-functor-1\">EXERCICE 36: functor</a></span></li></ul></div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 36: functor\n", + "\n", + "Replace method `Do()` in `TestDisplay` and its derived classes by a functor." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "© _CNRS 2016_ - _Inria 2018_ \n", + "_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n", + "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "C++17", + "language": "C++17", + "name": "xeus-cling-cpp17" + }, + "language_info": { + "codemirror_mode": "text/x-c++src", + "file_extension": ".cpp", + "mimetype": "text/x-c++src", + "name": "c++", + "version": "-std=c++17" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of contents", + "title_sidebar": "Contents", + "toc_cell": true, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/3-Operators/TP/CMakeLists.txt b/3-Operators/TP/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4112ab86bfed9f86ea4421b5fbe478309efc00b0 --- /dev/null +++ b/3-Operators/TP/CMakeLists.txt @@ -0,0 +1,40 @@ +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) + + if(CXX_COMPILER_${_flag_var}_OK) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}") + endif() +endmacro() + + +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_Operators) + + +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") + + +add_executable(initial initial_file.cpp) +add_executable(exercice31 exercice31.cpp) +add_executable(exercice32 exercice32.cpp) +add_executable(exercice33 exercice33.cpp) +add_executable(exercice34 exercice34.cpp) +add_executable(exercice35 exercice35.cpp) +add_executable(exercice36 exercice36.cpp) \ No newline at end of file diff --git a/3-Operators/TP/Solution/exercice31.cpp b/3-Operators/TP/Solution/exercice31.cpp new file mode 100644 index 0000000000000000000000000000000000000000..085f506936b2f12a451e2af436a378572baaf897 --- /dev/null +++ b/3-Operators/TP/Solution/exercice31.cpp @@ -0,0 +1,500 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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_`. + 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. + */ + int Multiply(int coefficient); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + + +/*! + * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. + */ +class TestDisplay +{ +public: + + //! Constructor. + TestDisplay(int resolution); + + //! Virtual method. + virtual void Do(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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox065(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + +//! Run TestDisplayPowerOfTwoApprox for value 0.35 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + + +/*! + * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. + + */ +class TestDisplaySum : public TestDisplay +{ +public: + + //! Constructor. + TestDisplaySum(int resolution); + + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +private: + + //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. + void Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& GetElement(int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +PowerOfTwoApprox::operator double() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int PowerOfTwoApprox::Multiply(int coefficient) +{ + return times_power_of_2(Numerator() * coefficient, -Exponent()); +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + auto numerator = approx.Numerator(); + auto exponent = approx.Exponent(); + + double double_approx = static_cast<double>(approx); + + std::ostringstream oconv; + oconv << " (" << numerator << "/2^" << exponent << ")"; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::Do(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = approx1.Multiply(coefficient1) + approx2.Multiply(coefficient2); + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::GetElement(int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::GetElement() request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container.GetElement(position); + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display.Do(Nbits); + + std::cout << std::endl; + } +} + + + diff --git a/3-Operators/TP/Solution/exercice32.cpp b/3-Operators/TP/Solution/exercice32.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4d5c5902a670ca94f54a329e3f2c76f5ef4f3b7 --- /dev/null +++ b/3-Operators/TP/Solution/exercice32.cpp @@ -0,0 +1,500 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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_`. + 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. + */ + int operator*(int coefficient); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + + +/*! + * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. + */ +class TestDisplay +{ +public: + + //! Constructor. + TestDisplay(int resolution); + + //! Virtual method. + virtual void Do(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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox065(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + +//! Run TestDisplayPowerOfTwoApprox for value 0.35 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + + +/*! + * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. + + */ +class TestDisplaySum : public TestDisplay +{ +public: + + //! Constructor. + TestDisplaySum(int resolution); + + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +private: + + //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. + void Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& GetElement(int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +PowerOfTwoApprox::operator double() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int PowerOfTwoApprox::operator*(int coefficient) +{ + return times_power_of_2(Numerator() * coefficient, -Exponent()); +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + auto numerator = approx.Numerator(); + auto exponent = approx.Exponent(); + + double double_approx = static_cast<double>(approx); + + std::ostringstream oconv; + oconv << " (" << numerator << "/2^" << exponent << ")"; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::Do(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = approx1 * coefficient1 + approx2 * coefficient2; + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::GetElement(int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::GetElement() request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container.GetElement(position); + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display.Do(Nbits); + + std::cout << std::endl; + } +} + + + diff --git a/3-Operators/TP/Solution/exercice33.cpp b/3-Operators/TP/Solution/exercice33.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39447981b0cc45d7092872905e675386a701079d --- /dev/null +++ b/3-Operators/TP/Solution/exercice33.cpp @@ -0,0 +1,508 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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. + */ + friend int operator*(const PowerOfTwoApprox& approx, int coefficient); + + friend int operator*(int coefficient, const PowerOfTwoApprox& approx); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + + +/*! + * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. + */ +class TestDisplay +{ +public: + + //! Constructor. + TestDisplay(int resolution); + + //! Virtual method. + virtual void Do(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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox065(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + +//! Run TestDisplayPowerOfTwoApprox for value 0.35 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + + +/*! + * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. + + */ +class TestDisplaySum : public TestDisplay +{ +public: + + //! Constructor. + TestDisplaySum(int resolution); + + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +private: + + //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. + void Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& GetElement(int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +PowerOfTwoApprox::operator double() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int operator*(const PowerOfTwoApprox& approx, int coefficient) +{ + return times_power_of_2(approx.Numerator() * coefficient, -approx.Exponent()); +} + + +int operator*(int coefficient, const PowerOfTwoApprox& approx) +{ + return approx * coefficient; +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + auto numerator = approx.Numerator(); + auto exponent = approx.Exponent(); + + double double_approx = static_cast<double>(approx); + + std::ostringstream oconv; + oconv << " (" << numerator << "/2^" << exponent << ")"; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::Do(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = coefficient1 * approx1 + coefficient2 * approx2; + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::GetElement(int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::GetElement() request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container.GetElement(position); + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display.Do(Nbits); + + std::cout << std::endl; + } +} + + + diff --git a/3-Operators/TP/Solution/exercice34.cpp b/3-Operators/TP/Solution/exercice34.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0329a223e9145feb03b2d388b9c66816350ceab5 --- /dev/null +++ b/3-Operators/TP/Solution/exercice34.cpp @@ -0,0 +1,508 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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. + */ + friend int operator*(const PowerOfTwoApprox& approx, int coefficient); + + friend int operator*(int coefficient, const PowerOfTwoApprox& approx); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + + +/*! + * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. + */ +class TestDisplay +{ +public: + + //! Constructor. + TestDisplay(int resolution); + + //! Virtual method. + virtual void Do(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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox065(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + +//! Run TestDisplayPowerOfTwoApprox for value 0.35 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + + +/*! + * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. + + */ +class TestDisplaySum : public TestDisplay +{ +public: + + //! Constructor. + TestDisplaySum(int resolution); + + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +private: + + //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. + void Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& operator[](int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +PowerOfTwoApprox::operator double() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int operator*(const PowerOfTwoApprox& approx, int coefficient) +{ + return times_power_of_2(approx.Numerator() * coefficient, -approx.Exponent()); +} + + +int operator*(int coefficient, const PowerOfTwoApprox& approx) +{ + return approx * coefficient; +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + auto numerator = approx.Numerator(); + auto exponent = approx.Exponent(); + + double double_approx = static_cast<double>(approx); + + std::ostringstream oconv; + oconv << " (" << numerator << "/2^" << exponent << ")"; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::Do(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = coefficient1 * approx1 + coefficient2 * approx2; + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::operator[](int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::operator[] request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container[position]; + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display.Do(Nbits); + + std::cout << std::endl; + } +} + + + diff --git a/3-Operators/TP/Solution/exercice35.cpp b/3-Operators/TP/Solution/exercice35.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5c88d06204d10a428241ef5ae8732cc95ee84c3 --- /dev/null +++ b/3-Operators/TP/Solution/exercice35.cpp @@ -0,0 +1,529 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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. + */ + friend int operator*(const PowerOfTwoApprox& approx, int coefficient); + + friend int operator*(int coefficient, const PowerOfTwoApprox& approx); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + +namespace std +{ + + + std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox& approx); + + +} // namespace std + + + +/*! + * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. + */ +class TestDisplay +{ +public: + + //! Constructor. + TestDisplay(int resolution); + + //! Virtual method. + virtual void Do(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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox065(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + +//! Run TestDisplayPowerOfTwoApprox for value 0.35 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + + +/*! + * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. + + */ +class TestDisplaySum : public TestDisplay +{ +public: + + //! Constructor. + TestDisplaySum(int resolution); + + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +private: + + //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. + void Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& operator[](int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +PowerOfTwoApprox::operator double() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int operator*(const PowerOfTwoApprox& approx, int coefficient) +{ + return times_power_of_2(approx.Numerator() * coefficient, -approx.Exponent()); +} + + +int operator*(int coefficient, const PowerOfTwoApprox& approx) +{ + return approx * coefficient; +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + double double_approx = static_cast<double>(approx); + + std::ostringstream oconv; + oconv << " (" << approx << ')'; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::Do(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = coefficient1 * approx1 + coefficient2 * approx2; + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::operator[](int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::operator[] request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container[position]; + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display.Do(Nbits); + + std::cout << std::endl; + } +} + + +namespace std +{ + + + std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox& approx) + { + out << approx.Numerator() << "/2^" << approx.Exponent(); + return out; + } + + +} // namespace std + + + diff --git a/3-Operators/TP/Solution/exercice36.cpp b/3-Operators/TP/Solution/exercice36.cpp new file mode 100644 index 0000000000000000000000000000000000000000..778c8a514fdbd9c520dca4fc4eddb99916b4c476 --- /dev/null +++ b/3-Operators/TP/Solution/exercice36.cpp @@ -0,0 +1,529 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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. + */ + friend int operator*(const PowerOfTwoApprox& approx, int coefficient); + + friend int operator*(int coefficient, const PowerOfTwoApprox& approx); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + +namespace std +{ + + + std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox& approx); + + +} // namespace std + + + +/*! + * \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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! 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 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! 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. + + */ +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, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& operator[](int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +PowerOfTwoApprox::operator double() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int operator*(const PowerOfTwoApprox& approx, int coefficient) +{ + return times_power_of_2(approx.Numerator() * coefficient, -approx.Exponent()); +} + + +int operator*(int coefficient, const PowerOfTwoApprox& approx) +{ + return approx * coefficient; +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + double double_approx = static_cast<double>(approx); + + std::ostringstream oconv; + oconv << " (" << approx << ')'; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::operator()(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::operator()(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::operator()(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = coefficient1 * approx1 + coefficient2 * approx2; + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::operator[](int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::operator[] request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container[position]; + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display(Nbits); + + std::cout << std::endl; + } +} + + +namespace std +{ + + + std::ostream& operator<<(std::ostream& out, const PowerOfTwoApprox& approx) + { + out << approx.Numerator() << "/2^" << approx.Exponent(); + return out; + } + + +} // namespace std + + + diff --git a/3-Operators/TP/initial_file.cpp b/3-Operators/TP/initial_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c539ed02067ecb88d4c4fc58576f9279a641c3ce --- /dev/null +++ b/3-Operators/TP/initial_file.cpp @@ -0,0 +1,500 @@ +#include <iostream> +#include <cmath> // for std::round +#include <string> +#include <sstream> // for std::ostringstream + + +/************************************/ +// Declarations +/************************************/ + +/*! + * \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. + */ +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_`. + double DoubleValue() 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. + */ + int Multiply(int coefficient); + + //! Get the value of the numerator. + int Numerator() const; + + //! Get the value of the exponent. + int Exponent() const; + +private: + + //! Numerator. + int numerator_ = 0; + + //! Exponent applied to the 2 at the denominator. + int exponent_ = 0; +}; + + + +/*! + * \brief Base class for TestDisplayPowerOfTwoApprox and TestDisplaySum. + */ +class TestDisplay +{ +public: + + //! Constructor. + TestDisplay(int resolution); + + //! Virtual method. + virtual void Do(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; + + +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. + */ +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 +class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox065(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + +//! Run TestDisplayPowerOfTwoApprox for value 0.35 +class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox +{ +public: + + //! Constructor. + TestDisplayPowerOfTwoApprox035(int resolution); + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const override; + +}; + + + +/*! + * \brief Class in charge of displaying the approximation for 0.65 * 3515 + 0.35 * 4832. + + */ +class TestDisplaySum : public TestDisplay +{ +public: + + //! Constructor. + TestDisplaySum(int resolution); + + + //! Print the output for the values 0.65 and 0.35. + void Do(int Nbits) const; + +private: + + //! Print the output for the approximation of the sum value1 * coefficient1 + value2 * coefficient2. + void Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const; + +}; + + +//! Returns `number` * (2 ^ `exponent`) +int times_power_of_2(int number, int exponent); + + +//! Round to `x` the nearest integer. +int round_as_int(double x); + + +//! Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits); + + +//! Function to call when an error occurred; its aborts the program. +[[noreturn]] void error(std::string explanation); + + +//! Class which stores several `TestDisplay` as pointers. +class TestDisplayContainer +{ +public: + + //! Constructor. + TestDisplayContainer(std::size_t size); + + //! Destructor. + ~TestDisplayContainer(); + + //! Insert a new `TestDisplay` object at the `next_position_available_`. + void Register(TestDisplay* test_display); + + //! Returns the number of registered elements. + int Nelement() const; + + //! Provide access to the `i`-th element. + TestDisplay& GetElement(int i) const; + +private: + + //! Store `TestDisplay` objects upon which the display will be called. + TestDisplay** test_display_list_; + + //! Size of the array. + const std::size_t size_ = 0; + + //! Position in which the next `TestDisplay` will be put. + int next_position_available_ = 0; +}; + + +//! Loop over the content of `TestDisplayContainer`. +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& 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 + + TestDisplayContainer container(3); + container.Register(new TestDisplayPowerOfTwoApprox065(1000000)); + container.Register(new TestDisplayPowerOfTwoApprox035(1000000)); + container.Register(new TestDisplaySum(1000000)); + + loop(4, 16, 4, container); + + return EXIT_SUCCESS; +} + + +/************************************/ +// Definitions +/************************************/ + + +int times_power_of_2(int number, int exponent) +{ + while (exponent > 0) + { + number *= 2; + exponent -= 1; + } + while (exponent < 0) + { + number /= 2; + exponent += 1 ; + } + + return number; +} + + +int round_as_int(double x) +{ + return static_cast<int>(std::round(x)); +} + + +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +[[noreturn]] void error(std::string explanation) +{ + std::cout << "ERROR: " << explanation << std::endl; + exit(EXIT_FAILURE); +} + + +/*==================================*/ +// PowerOfTwoApprox +/*==================================*/ + +PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value) +{ + auto& numerator = numerator_; + auto& exponent = exponent_; + + numerator = exponent = 0; + int denominator {}; + + int max_numerator = max_int(Nbits); + + do + { + ++exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); + } + while (numerator <= max_numerator); + + --exponent; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +double PowerOfTwoApprox::DoubleValue() const +{ + int denominator = times_power_of_2(1, exponent_); + return static_cast<double>(numerator_) / denominator; +} + + +int PowerOfTwoApprox::Numerator() const +{ + return numerator_; +} + + +int PowerOfTwoApprox::Exponent() const +{ + return exponent_; +} + + +int PowerOfTwoApprox::Multiply(int coefficient) +{ + return times_power_of_2(Numerator() * coefficient, -Exponent()); +} + + +/*==================================*/ +// TestDisplay +/*==================================*/ + +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(resolution_ * std::fabs(exact - approx) / exact); + + std::cout << "[With " << Nbits << " bits]: " << after_bit_string + << exact << " ~ " << approx + << before_error + << " [error = " << error << "/" << resolution_ << "]" + << std::endl; +} + + +/*==================================*/ +// TestDisplayPowerOfTwoApprox +/*==================================*/ + +TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution) +: TestDisplay(resolution) +{ } + + +TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default; + + +void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const +{ + PowerOfTwoApprox approx(Nbits, value); + + auto numerator = approx.Numerator(); + auto exponent = approx.Exponent(); + + double double_approx = approx.DoubleValue(); + + std::ostringstream oconv; + oconv << " (" << numerator << "/2^" << exponent << ")"; + + PrintNumericalError(Nbits, value, double_approx, "", oconv.str()); +} + + +TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution) +: TestDisplayPowerOfTwoApprox(resolution) +{ } + + +void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const +{ + Display(Nbits, 0.65); +} + + +void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const +{ + Display(Nbits, 0.35); +} + + + +/*==================================*/ +// TestDisplaySum +/*==================================*/ + +TestDisplaySum::TestDisplaySum(int resolution) +: TestDisplay(resolution) +{ } + + +void TestDisplaySum::Do(int Nbits) const +{ + Display(Nbits, 0.65, 3515, 0.35, 4832); +} + + +void TestDisplaySum::Display(int Nbits, double value1, int coefficient1, double value2, int coefficient2) const +{ + double exact = std::round(value1 * coefficient1 + value2 * coefficient2); + + PowerOfTwoApprox approx1(Nbits, value1); + PowerOfTwoApprox approx2(Nbits, value2); + + int approx = approx1.Multiply(coefficient1) + approx2.Multiply(coefficient2); + + std::ostringstream oconv; + oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = "; + + PrintNumericalError(Nbits, exact, static_cast<double>(approx), oconv.str(), ""); +} + + +/*==================================*/ +// TestDisplayContainer +/*==================================*/ + +TestDisplayContainer::TestDisplayContainer(std::size_t size) +: size_(size) +{ + test_display_list_ = new TestDisplay*[size]; + + for (auto i = 0ul; i < size; ++i) + test_display_list_[i] = nullptr; +} + + +TestDisplayContainer::~TestDisplayContainer() +{ + for (int position = 0; position < next_position_available_; ++position) + delete test_display_list_[position]; + + delete[] test_display_list_; +} + + +void TestDisplayContainer::Register(TestDisplay* test_display) +{ + if (next_position_available_ >= static_cast<int>(size_)) + error("Too many `TestDisplay` registered!"); + + test_display_list_[next_position_available_++] = test_display; +} + + +int TestDisplayContainer::Nelement() const +{ + return next_position_available_; +} + + +TestDisplay& TestDisplayContainer::GetElement(int i) const +{ + if (i < 0 || i >= next_position_available_) + error("Invalid index in TestDisplayContainer::GetElement() request!"); + + decltype(auto) element_ptr = test_display_list_[i]; + return *element_ptr; +} + + + +void loop(int Nbits_min, int Nbits_max, int Nbits_increment, TestDisplayContainer& container) +{ + int Nelement = container.Nelement(); + + for (int position = 0; position < Nelement; ++position) + { + decltype(auto) test_display = container.GetElement(position); + + for (int Nbits = Nbits_min; Nbits <= Nbits_max; Nbits += Nbits_increment) + test_display.Do(Nbits); + + std::cout << std::endl; + } +} + + + diff --git a/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb b/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb index 6a344bcf549ecfe6e06660e981de8b11f22c4984..ac1ea7b677224018ded24378b8de05037c2fe506 100644 --- a/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb +++ b/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb @@ -96,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ diff --git a/6-InRealEnvironment/Docker/ThirdPartyWarning/1-ProblematicCase/CMakeLists.txt b/6-InRealEnvironment/Docker/ThirdPartyWarning/1-ProblematicCase/CMakeLists.txt index beda9cb93a07517f7a8ba359649afeda17b322b7..3793468c08be9e833933b908e387d22d730d015e 100644 --- a/6-InRealEnvironment/Docker/ThirdPartyWarning/1-ProblematicCase/CMakeLists.txt +++ b/6-InRealEnvironment/Docker/ThirdPartyWarning/1-ProblematicCase/CMakeLists.txt @@ -13,6 +13,13 @@ macro(add_cxx_compiler_flag _flag) endif() endmacro() +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_SimpleBoost) + 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) diff --git a/6-InRealEnvironment/Docker/ThirdPartyWarning/2-FixByBuildSystem/CMakeLists.txt b/6-InRealEnvironment/Docker/ThirdPartyWarning/2-FixByBuildSystem/CMakeLists.txt index db2608d1e43a0950c304785c8bef11001a90dbb8..4e2f7aa143bb3f34cefec68741989724c78fdb54 100644 --- a/6-InRealEnvironment/Docker/ThirdPartyWarning/2-FixByBuildSystem/CMakeLists.txt +++ b/6-InRealEnvironment/Docker/ThirdPartyWarning/2-FixByBuildSystem/CMakeLists.txt @@ -13,6 +13,14 @@ macro(add_cxx_compiler_flag _flag) endif() endmacro() + +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_Operators) + 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) diff --git a/6-InRealEnvironment/Docker/ThirdPartyWarning/3-FixByPragmas-clang/CMakeLists.txt b/6-InRealEnvironment/Docker/ThirdPartyWarning/3-FixByPragmas-clang/CMakeLists.txt index beda9cb93a07517f7a8ba359649afeda17b322b7..0fd6382eecf41f1ab36ec23944a0b1122b98f403 100644 --- a/6-InRealEnvironment/Docker/ThirdPartyWarning/3-FixByPragmas-clang/CMakeLists.txt +++ b/6-InRealEnvironment/Docker/ThirdPartyWarning/3-FixByPragmas-clang/CMakeLists.txt @@ -13,6 +13,13 @@ macro(add_cxx_compiler_flag _flag) endif() endmacro() +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) + 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) diff --git a/6-InRealEnvironment/Docker/ThirdPartyWarning/4-FixByPragmas-clang-gcc/CMakeLists.txt b/6-InRealEnvironment/Docker/ThirdPartyWarning/4-FixByPragmas-clang-gcc/CMakeLists.txt index beda9cb93a07517f7a8ba359649afeda17b322b7..0fd6382eecf41f1ab36ec23944a0b1122b98f403 100644 --- a/6-InRealEnvironment/Docker/ThirdPartyWarning/4-FixByPragmas-clang-gcc/CMakeLists.txt +++ b/6-InRealEnvironment/Docker/ThirdPartyWarning/4-FixByPragmas-clang-gcc/CMakeLists.txt @@ -13,6 +13,13 @@ macro(add_cxx_compiler_flag _flag) endif() endmacro() +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) + 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) diff --git a/6-InRealEnvironment/Docker/ThirdPartyWarning/5-FixByPragmas-common/CMakeLists.txt b/6-InRealEnvironment/Docker/ThirdPartyWarning/5-FixByPragmas-common/CMakeLists.txt index beda9cb93a07517f7a8ba359649afeda17b322b7..0fd6382eecf41f1ab36ec23944a0b1122b98f403 100644 --- a/6-InRealEnvironment/Docker/ThirdPartyWarning/5-FixByPragmas-common/CMakeLists.txt +++ b/6-InRealEnvironment/Docker/ThirdPartyWarning/5-FixByPragmas-common/CMakeLists.txt @@ -13,6 +13,13 @@ macro(add_cxx_compiler_flag _flag) endif() endmacro() +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) + 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) diff --git a/TP/HowTo.ipynb b/TP/HowTo.ipynb index a1cb1f11f7dd8c0d6bc4ce18820bbb3119905c72..9825c829856421f9c0bc0cddd42fd05f3d634f2e 100644 --- a/TP/HowTo.ipynb +++ b/TP/HowTo.ipynb @@ -85,7 +85,7 @@ "\n", "The steps to compile are the same as presented in the previous section.\n", "\n", - "For more informations about the Docker way please look the dedicated [README](https://gitlab.inria.fr/formations/cpp/gettingstartedwithmoderncpp/blob/master/TP/README.md).\n" + "For more informations about the Docker way please look the dedicated [README](https://gitlab.inria.fr/formations/cpp/gettingstartedwithmoderncpp/blob/master/TP/README.md) (the one within the TP folder of the root directory).\n" ] }, {