diff --git a/1-ProceduralProgramming/0-main.ipynb b/1-ProceduralProgramming/0-main.ipynb index 5743dcabb0893751e848a822ff4ae3eb24199f8e..570fdee6484eb72636a1e92d3c711b1f8e5e20b5 100644 --- a/1-ProceduralProgramming/0-main.ipynb +++ b/1-ProceduralProgramming/0-main.ipynb @@ -13,12 +13,13 @@ "source": [ "* [Variables, initialisation, affectation](/notebooks/1-ProceduralProgramming/1-Variables.ipynb)\n", "* [Condition and loops](/notebooks/1-ProceduralProgramming/2-Conditions-and-loops.ipynb)\n", + " * [TP 1](/notebooks/1-ProceduralProgramming/2b-TP.ipynb)\n", "* [Predefined types](/notebooks/1-ProceduralProgramming/3-Types.ipynb)\n", "* [Functions](/notebooks/1-ProceduralProgramming/4-Functions.ipynb)\n", - " * [TP 1](/notebooks/1-ProceduralProgramming/4b-TP.ipynb)\n", + " * [TP 2](/notebooks/1-ProceduralProgramming/4b-TP.ipynb)\n", "* [Dynamic allocation](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb)\n", "* [Input/output](/notebooks/1-ProceduralProgramming/6-Streams.ipynb)\n", - " * [TP 2](/notebooks/1-ProceduralProgramming/6b-TP.ipynb)" + " * [TP 3](/notebooks/1-ProceduralProgramming/6b-TP.ipynb)" ] }, { diff --git a/1-ProceduralProgramming/2b-TP.ipynb b/1-ProceduralProgramming/2b-TP.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..9d7ae0906108c092f2cf08bf62202be20fccdb60 --- /dev/null +++ b/1-ProceduralProgramming/2b-TP.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 1](/notebooks/1-ProceduralProgramming/4b-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><ul class=\"toc-item\"><li><span><a href=\"#How-to-do-the-TP?\" data-toc-modified-id=\"How-to-do-the-TP?-1.1\">How to do the TP?</a></span></li><li><span><a href=\"#The-problem-we'll-deal-with-throughout-the-TPs\" data-toc-modified-id=\"The-problem-we'll-deal-with-throughout-the-TPs-1.2\">The problem we'll deal with throughout the TPs</a></span></li><li><span><a href=\"#EXERCICE-1:-Adding-a-loop\" data-toc-modified-id=\"EXERCICE-1:-Adding-a-loop-1.3\"><strong>EXERCICE 1: Adding a loop</strong></a></span></li></ul></li></ul></div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "### How to do the TP?\n", + "\n", + "This [notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.\n", + "\n", + "### The problem we'll deal with throughout the TPs\n", + "\n", + "Any real number can be approximated by the ratio between two integers. \n", + "\n", + "We will choose here to approximate any real `r` by an expression `numerator / 2^exponent`, where both `numerator` and `exponent` are integers.\n", + "\n", + "The higher the numerator and exponent values, the more accurate the approximation can be. For example, 0.65 can be approximated successively by: \n", + "* 1 / 2<sup>1</sup> = 0.5 \n", + "* 3 / 2<sup>2</sup> = 0.75 \n", + "* 5 / 2<sup>3</sup> = 0.625\n", + "* ... \n", + "\n", + "The highest possible numbers will therefore be chosen, within the limits set by the system, i.e. by the number of bits available to encode these numbers.\n", + "\n", + "As part of the TP, the number of bits allowed to store the numerator will be arbitrarily fixed, and the effect on the accuracy of the approximation will be calculated. Note that if you have N bits to store an integer, the largest possible integer is 2<sup>N</sup> - 1.\n", + "\n", + "The file you need to start is [provided](/notebooks/TP/1-ProceduralProgramming/initial_file.cpp) in the TP folder of ProceduralProgramming lectures." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### __EXERCICE 1: Adding a loop__\n", + "\n", + "Write a loop that displays the like of above up to the 2<sup>8</sup> for 0.65.\n", + "\n", + "_Expected result_:\n", + "\n", + "0.65 ~ 1 / 2^1 \n", + "0.65 ~ 3 / 2^2 \n", + "0.65 ~ 5 / 2^3 \n", + "0.65 ~ 10 / 2^4 \n", + "0.65 ~ 21 / 2^5 \n", + "0.65 ~ 42 / 2^6 \n", + "0.65 ~ 83 / 2^7 \n", + "0.65 ~ 166 / 2^8" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "© _CNRS 2016_ - _Inria 2018-2019_ \n", + "_This notebook is an adaptation of a lecture prepared 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 written by Sébastien Gilles and Vincent Rouvreau (Inria)_\n", + "\n" + ] + } + ], + "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": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "285.2px" + }, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/1-ProceduralProgramming/4b-TP.ipynb b/1-ProceduralProgramming/4b-TP.ipynb index 8e6dfc26207bf6e200d3548437ffa5368978452e..6f77c33a4b3b0a5da1a30d830f4fbb329e08020e 100644 --- a/1-ProceduralProgramming/4b-TP.ipynb +++ b/1-ProceduralProgramming/4b-TP.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 1](/notebooks/1-ProceduralProgramming/4b-TP.ipynb)" + "# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 2](/notebooks/1-ProceduralProgramming/4b-TP.ipynb)" ] }, { @@ -14,56 +14,7 @@ }, "source": [ "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n", - "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span><ul class=\"toc-item\"><li><span><a href=\"#How-to-do-the-TP?\" data-toc-modified-id=\"How-to-do-the-TP?-1.1\">How to do the TP?</a></span></li><li><span><a href=\"#The-problem-we'll-deal-with-throughout-the-TPs\" data-toc-modified-id=\"The-problem-we'll-deal-with-throughout-the-TPs-1.2\">The problem we'll deal with throughout the TPs</a></span></li><li><span><a href=\"#EXERCICE-1:-Adding-a-loop\" data-toc-modified-id=\"EXERCICE-1:-Adding-a-loop-1.3\"><strong>EXERCICE 1: Adding a loop</strong></a></span></li><li><span><a href=\"#EXERCICE-2:-Adding-a-function\" data-toc-modified-id=\"EXERCICE-2:-Adding-a-function-1.4\"><strong>EXERCICE 2: Adding a function</strong></a></span></li><li><span><a href=\"#EXERCICE-3:-compute-the-approximation\" data-toc-modified-id=\"EXERCICE-3:-compute-the-approximation-1.5\"><strong>EXERCICE 3: compute the approximation</strong></a></span></li><li><span><a href=\"#EXERCICE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator.\" data-toc-modified-id=\"EXERCICE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator.-1.6\"><strong>EXERCICE 4: Search for the best approximation for a given maximum numerator.</strong></a></span></li><li><span><a href=\"#EXERCICE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits\" data-toc-modified-id=\"EXERCICE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits-1.7\"><strong>EXERCICE 5: Computation of the maximum numerator as a function of the number of bits</strong></a></span></li><li><span><a href=\"#EXERCICE-6:-moving-display-to-a-new-intermediate-function\" data-toc-modified-id=\"EXERCICE-6:-moving-display-to-a-new-intermediate-function-1.8\"><strong>EXERCICE 6: moving display to a new intermediate function</strong></a></span></li><li><span><a href=\"#EXERCICE-7:-adding-error-in-display\" data-toc-modified-id=\"EXERCICE-7:-adding-error-in-display-1.9\"><strong>EXERCICE 7: adding error in display</strong></a></span></li><li><span><a href=\"#EXERCICE-8:-Multiplication\" data-toc-modified-id=\"EXERCICE-8:-Multiplication-1.10\"><strong>EXERCICE 8: Multiplication</strong></a></span></li><li><span><a href=\"#EXERCICE-9:-display-sum-of-two-multiply\" data-toc-modified-id=\"EXERCICE-9:-display-sum-of-two-multiply-1.11\">EXERCICE 9: display sum of two <code>multiply</code></a></span></li><li><span><a href=\"#EXERCICE-10:-print-error-in-display_sum()\" data-toc-modified-id=\"EXERCICE-10:-print-error-in-display_sum()-1.12\"><strong>EXERCICE 10: print error in <code>display_sum()</code></strong></a></span></li><li><span><a href=\"#EXERCICE-11:-function-pointers\" data-toc-modified-id=\"EXERCICE-11:-function-pointers-1.13\">EXERCICE 11: function pointers</a></span></li></ul></li></ul></div>" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction\n", - "\n", - "### How to do the TP?\n", - "\n", - "This [notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.\n", - "\n", - "### The problem we'll deal with throughout the TPs\n", - "\n", - "Any real number can be approximated by the ratio between two integers. \n", - "\n", - "We will choose here to approximate any real `r` by an expression `numerator / 2^exponent`, where both `numerator` and `exponent` are integers.\n", - "\n", - "The higher the numerator and exponent values, the more accurate the approximation can be. For example, 0.65 can be approximated successively by: \n", - "* 1 / 2<sup>1</sup> = 0.5 \n", - "* 3 / 2<sup>2</sup> = 0.75 \n", - "* 5 / 2<sup>3</sup> = 0.625\n", - "* ... \n", - "\n", - "The highest possible numbers will therefore be chosen, within the limits set by the system, i.e. by the number of bits available to encode these numbers.\n", - "\n", - "As part of the TP, the number of bits allowed to store the numerator will be arbitrarily fixed, and the effect on the accuracy of the approximation will be calculated. Note that if you have N bits to store an integer, the largest possible integer is 2<sup>N</sup> - 1.\n", - "\n", - "The file you need to start is [provided](/notebooks/TP/1-ProceduralProgramming/initial_file.cpp) in the TP folder of ProceduralProgramming lectures." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### __EXERCICE 1: Adding a loop__\n", - "\n", - "Write a loop that displays the like of above up to the 2<sup>8</sup> for 0.65.\n", - "\n", - "_Expected result_:\n", - "\n", - "0.65 ~ 1 / 2^1 \n", - "0.65 ~ 3 / 2^2 \n", - "0.65 ~ 5 / 2^3 \n", - "0.65 ~ 10 / 2^4 \n", - "0.65 ~ 21 / 2^5 \n", - "0.65 ~ 42 / 2^6 \n", - "0.65 ~ 83 / 2^7 \n", - "0.65 ~ 166 / 2^8" + "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-2:-Adding-a-function\" data-toc-modified-id=\"EXERCICE-2:-Adding-a-function-1\"><strong>EXERCICE 2: Adding a function</strong></a></span></li><li><span><a href=\"#EXERCICE-3:-compute-the-approximation\" data-toc-modified-id=\"EXERCICE-3:-compute-the-approximation-2\"><strong>EXERCICE 3: compute the approximation</strong></a></span></li><li><span><a href=\"#EXERCICE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator.\" data-toc-modified-id=\"EXERCICE-4:-Search-for-the-best-approximation-for-a-given-maximum-numerator.-3\"><strong>EXERCICE 4: Search for the best approximation for a given maximum numerator.</strong></a></span></li><li><span><a href=\"#EXERCICE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits\" data-toc-modified-id=\"EXERCICE-5:-Computation-of-the-maximum-numerator-as-a-function-of-the-number-of-bits-4\"><strong>EXERCICE 5: Computation of the maximum numerator as a function of the number of bits</strong></a></span></li><li><span><a href=\"#EXERCICE-6:-moving-display-to-a-new-intermediate-function\" data-toc-modified-id=\"EXERCICE-6:-moving-display-to-a-new-intermediate-function-5\"><strong>EXERCICE 6: moving display to a new intermediate function</strong></a></span></li><li><span><a href=\"#EXERCICE-7:-adding-error-in-display\" data-toc-modified-id=\"EXERCICE-7:-adding-error-in-display-6\"><strong>EXERCICE 7: adding error in display</strong></a></span></li></ul></div>" ] }, { @@ -169,11 +120,11 @@ "source": [ "int main()\n", "{\n", - " display_power_of_2_approx(15, 0.65) ;\n", - " display_power_of_2_approx(255, 0.65) ;\n", + " display_power_of_2_approx(15, 0.65);\n", + " display_power_of_2_approx(255, 0.65);\n", "\n", - " display_power_of_2_approx(15, 0.35) ;\n", - " display_power_of_2_approx(255, 0.35) ;\n", + " display_power_of_2_approx(15, 0.35);\n", + " display_power_of_2_approx(255, 0.35);\n", "\n", " return EXIT_SUCCESS;\n", "}" @@ -201,11 +152,9 @@ "\n", "The highest usable value for the numerator depends on the number of bits used to represent this integer. \n", "\n", - "In `display_power_of_2_approx()` arguments, replace the argument designating the maximum value with an argument designating the maximum number of bits and correct the body of the function accordingly, using the `max_int()` function given below.\n", - "\n", - "On display, replace the maximum numerator with the number of bits. \n", + "In `display_power_of_2_approx()` arguments, replace the argument designating the maximum numerator with an argument designating the maximum number of bits and correct the body of the function accordingly, using the `max_int()` function given below.\n", "\n", - "In the main program, make two loops that vary the number of bits from 2 to 8 in steps of 2, one that calls `display_power_of_2_approx()` for 0.65, and the other for 0.35. " + "On display, replace the maximum numerator with the number of bits. \n" ] }, { @@ -221,6 +170,36 @@ "}" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the following `main()` function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "int main(int argc, char** argv)\n", + "{\n", + " static_cast<void>(argc); // to silence warning about unused argc - don't bother \n", + " static_cast<void>(argv); // to silence warning about unused argv - don't bother \n", + " \n", + " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", + " display_power_of_2_approx(Nbits, 0.65);\n", + " \n", + " std::cout << std::endl;\n", + "\n", + " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", + " display_power_of_2_approx(Nbits, 0.35);\n", + "\n", + " return EXIT_SUCCESS;\n", + "}" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -253,7 +232,11 @@ "\n", "It is often advisable to give one main functionality to a given function; we will thefore separate here the computation from the display.\n", "\n", - "Write a new function named `compute_power_of_2_approx()`, which computes the approximation itself and returns the numerator and the exponent as output arguments; this function will be called in `display_power_of_2_approx()`.\n", + "Write a new function named `compute_power_of_2_approx()` that will be called in `display_power_of_2_approx()`.\n", + "\n", + "This new function should:\n", + "* Return the floating point approximation.\n", + "* Return (with reference parameters) the numerator and the exponent (that are displayed on screen).\n", "\n", "Output should remain the same!\n" ] @@ -289,209 +272,6 @@ "````" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### __EXERCICE 8: Multiplication__\n", - "\n", - "Write the `multiply()` function that calculates the approximate product of a real by an integer coefficient and returns an integer. \n", - "\n", - "This function must approximate the real using the `compute_power_of_2_approx()` function above; the returned integer shall use `times_power_of_2()` function.\n", - "\n", - "The arguments of `multiply()` are the maximum number of bits for approximation, the real and the integer coefficient.\n", - "\n", - "The new main will be:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "int main(int argc, char** argv) \n", - "{ \n", - " static_cast<void>(argc); // to silence warning about unused argc - don't bother \n", - " static_cast<void>(argv); // to silence warning about unused argv - don't bother \n", - " \n", - " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", - " display_power_of_2_approx(Nbits, 0.65) ;\n", - " \n", - " std::cout << std::endl;\n", - "\n", - " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", - " display_power_of_2_approx(Nbits, 0.35) ;\n", - " \n", - " std::cout << std::endl;\n", - "\n", - " for (int Nbits = 1; Nbits <= 8; ++Nbits)\n", - " {\n", - " double exact = 0.65 * 3515 + 0.35 * 4832;\n", - " int rounded = round_as_int(exact);\n", - " int approx = multiply(Nbits, 0.65, 3515) + multiply(Nbits, 0.35, 4832);\n", - " std::cout << \"[With \" << Nbits << \" bits]: 0.65 * 3515 + 0.35 * 4832 = \" \n", - " << rounded << \" ~ \" << approx << std::endl;\n", - " }\n", - "\n", - " return EXIT_SUCCESS;\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "_Expected result:_\n", - "\n", - "````\n", - "[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]\n", - "[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]\n", - "[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]\n", - "[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]\n", - "\n", - "[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]\n", - "[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]\n", - "[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]\n", - "[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 0/100]\n", - "\n", - "[With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965\n", - "[With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448\n", - "[With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008\n", - "[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857\n", - "[With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967\n", - "[With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004\n", - "[With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977\n", - "[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968\n", - "````" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### EXERCICE 9: display sum of two `multiply`\n", - "\n", - "Exactly as we did previously in exercice 2, move the display of the sum of multiplication result in a dedicated function `display_sum()` (which will hence takes 5 arguments: number of bits, two reals and their associated integer coefficient).\n", - "\n", - "New main will look like:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "int main(int argc, char** argv)\n", - "{\n", - " static_cast<void>(argc); // to silence warning about unused argc - don't bother \n", - " static_cast<void>(argv); // to silence warning about unused argv - don't bother \n", - " \n", - " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", - " display_power_of_2_approx(0.65, Nbits);\n", - "\n", - " std::cout << std::endl;\n", - "\n", - " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", - " display_power_of_2_approx(0.35, Nbits);\n", - " \n", - " std::cout << std::endl;\n", - " \n", - " for (int Nbits = 1; Nbits <= 8; ++Nbits)\n", - " display_multiply(Nbits, 0.65, 3515, 0.35, 4832);\n", - " \n", - " return EXIT_SUCCESS;\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### __EXERCICE 10: print error in `display_sum()`__\n", - "\n", - "Modify slightly the function defined above to add display of the error; we will express it over 1000.\n", - "\n", - "_Expected result_:\n", - "\n", - "````\n", - "[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]\n", - "[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]\n", - "[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]\n", - "[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]\n", - "\n", - "[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]\n", - "[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]\n", - "[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]\n", - "[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 0/100]\n", - "\n", - "[With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965 [error = 254/1000]\n", - "[With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448 [error = 119/1000]\n", - "[With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008 [error = 8/1000]\n", - "[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 30/1000]\n", - "[With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967 [error = 2/1000]\n", - "[With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004 [error = 7/1000]\n", - "[With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977 [error = 0/1000]\n", - "[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2/1000]\n", - "````\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### EXERCICE 11: function pointers\n", - "\n", - "Create a `loop()` function that takes as an argument :\n", - "\n", - "* An initial number of bits\n", - "* A final number of bits\n", - "* An increment to be applied to the number of bits\n", - "* A pointer to a function to be executed for each number of bits\n", - "\n", - "You will need the following intermediate function to be able to use them in `loop()` (as a specific signature is expected):" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "void display_065(int Nbits)\n", - "{ \n", - " display_power_of_2_approx(Nbits, 0.65); \n", - "}\n", - "\n", - "void display_035(int Nbits)\n", - "{\n", - " display_power_of_2_approx(Nbits, 0.35); \n", - "}\n", - "\n", - "void display_065_3515_035_4832(int Nbits)\n", - "{ \n", - " display_sum(Nbits, 0.65, 3515, 0.35, 4832); \n", - "}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "int main()\n", - "{\n", - " loop(2, 8, 2, display_065) ;\n", - " loop(2, 8, 2, display_035) ;\n", - " loop(1, 8, 1, display_065_3515_035_4832) ;\n", - " return EXIT_SUCCESS;\n", - "}" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/1-ProceduralProgramming/6b-TP.ipynb b/1-ProceduralProgramming/6b-TP.ipynb index 2961976480826c0334d7e3724ec93f9cd301c662..7f7f5bea0ab7967babf8ea8a9ed4e3bec9554cde 100644 --- a/1-ProceduralProgramming/6b-TP.ipynb +++ b/1-ProceduralProgramming/6b-TP.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 1](/notebooks/1-ProceduralProgramming/7b-TP.ipynb)" + "# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 3](/notebooks/1-ProceduralProgramming/7b-TP.ipynb)" ] }, { @@ -14,14 +14,240 @@ }, "source": [ "<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n", - "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-12:-write-in-output-file\" data-toc-modified-id=\"EXERCICE-12:-write-in-output-file-1\">EXERCICE 12: write in output file</a></span></li></ul></div>" + "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-8:-Multiplication-by-an-integer\" data-toc-modified-id=\"EXERCICE-8:-Multiplication-by-an-integer-1\"><strong>EXERCICE 8: Multiplication by an integer</strong></a></span></li><li><span><a href=\"#EXERCICE-9:-display-sum-of-two-multiply\" data-toc-modified-id=\"EXERCICE-9:-display-sum-of-two-multiply-2\">EXERCICE 9: display sum of two <code>multiply</code></a></span></li><li><span><a href=\"#EXERCICE-10:-print-error-in-display_sum()\" data-toc-modified-id=\"EXERCICE-10:-print-error-in-display_sum()-3\"><strong>EXERCICE 10: print error in <code>display_sum()</code></strong></a></span></li><li><span><a href=\"#[optional]-EXERCICE-11:-function-pointers\" data-toc-modified-id=\"[optional]-EXERCICE-11:-function-pointers-4\">[optional] EXERCICE 11: function pointers</a></span></li><li><span><a href=\"#[optional]-EXERCICE-12:-write-in-output-file\" data-toc-modified-id=\"[optional]-EXERCICE-12:-write-in-output-file-5\">[optional] EXERCICE 12: write in output file</a></span></li></ul></div>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### EXERCICE 12: write in output file \n", + "### __EXERCICE 8: Multiplication by an integer__\n", + "\n", + "Write the `multiply()` function that calculates the approximate product of a real by an integer coefficient and returns an integer. \n", + "\n", + "This function must approximate the real using the `compute_power_of_2_approx()` function above; the returned integer shall use `times_power_of_2()` function.\n", + "\n", + "The arguments of `multiply()` are the maximum number of bits for approximation, the real and the integer coefficient.\n", + "\n", + "The new main will be:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "int main(int argc, char** argv) \n", + "{ \n", + " static_cast<void>(argc); // to silence warning about unused argc - don't bother \n", + " static_cast<void>(argv); // to silence warning about unused argv - don't bother \n", + " \n", + " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", + " display_power_of_2_approx(Nbits, 0.65) ;\n", + " \n", + " std::cout << std::endl;\n", + "\n", + " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", + " display_power_of_2_approx(Nbits, 0.35) ;\n", + " \n", + " std::cout << std::endl;\n", + "\n", + " for (int Nbits = 1; Nbits <= 8; ++Nbits)\n", + " {\n", + " double exact = 0.65 * 3515;\n", + " int rounded = round_as_int(exact);\n", + " int approx = multiply(Nbits, 0.65, 3515);\n", + " std::cout << \"[With \" << Nbits << \" bits]: 0.65 * 3515 = \" \n", + " << rounded << \" ~ \" << approx << std::endl;\n", + " }\n", + "\n", + " return EXIT_SUCCESS;\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_Expected result:_\n", + "\n", + "````\n", + "[With 2 bits]: 0.65 ~ 0.75 (3 / 2^2) [error = 15/100]\n", + "[With 4 bits]: 0.65 ~ 0.625 (10 / 2^4) [error = 4/100]\n", + "[With 6 bits]: 0.65 ~ 0.65625 (42 / 2^6) [error = 1/100]\n", + "[With 8 bits]: 0.65 ~ 0.648438 (166 / 2^8) [error = 0/100]\n", + "\n", + "[With 2 bits]: 0.35 ~ 0.375 (3 / 2^3) [error = 7/100]\n", + "[With 4 bits]: 0.35 ~ 0.34375 (11 / 2^5) [error = 2/100]\n", + "[With 6 bits]: 0.35 ~ 0.351562 (45 / 2^7) [error = 0/100]\n", + "[With 8 bits]: 0.35 ~ 0.349609 (179 / 2^9) [error = 0/100]\n", + "\n", + "[With 1 bits]: 0.65 * 3515 = 2285 ~ 1757\n", + "[With 2 bits]: 0.65 * 3515 = 2285 ~ 2636\n", + "[With 3 bits]: 0.65 * 3515 = 2285 ~ 2196\n", + "[With 4 bits]: 0.65 * 3515 = 2285 ~ 2196\n", + "[With 5 bits]: 0.65 * 3515 = 2285 ~ 2306\n", + "[With 6 bits]: 0.65 * 3515 = 2285 ~ 2306\n", + "[With 7 bits]: 0.65 * 3515 = 2285 ~ 2279\n", + "[With 8 bits]: 0.65 * 3515 = 2285 ~ 2279\n", + "````" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EXERCICE 9: display sum of two `multiply`\n", + "\n", + "Write a `display_sum` function which will write the computation of the sum of two real numbers through their approximation.\n", + "\n", + "This function will take 5 arguments:\n", + "\n", + "* The number of bits to use.\n", + "* Two real values.\n", + "* Their associated coefficients.\n", + "\n", + "New main will look like:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "int main(int argc, char** argv)\n", + "{\n", + " static_cast<void>(argc); // to silence warning about unused argc - don't bother \n", + " static_cast<void>(argv); // to silence warning about unused argv - don't bother \n", + " \n", + " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", + " display_power_of_2_approx(0.65, Nbits);\n", + "\n", + " std::cout << std::endl;\n", + "\n", + " for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n", + " display_power_of_2_approx(0.35, Nbits);\n", + " \n", + " std::cout << std::endl;\n", + " \n", + " for (int Nbits = 1; Nbits <= 8; ++Nbits)\n", + " display_multiply(Nbits, 0.65, 3515, 0.35, 4832); // to compute 0.65 * 3515 + 0.35 * 4832\n", + " \n", + " return EXIT_SUCCESS;\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_Expected result_:\n", + "\n", + " [With 2 bits]: 0.65 ~ 0.75 (3 / 2^2) [error = 15/100]\n", + " [With 4 bits]: 0.65 ~ 0.625 (10 / 2^4) [error = 4/100]\n", + " [With 6 bits]: 0.65 ~ 0.65625 (42 / 2^6) [error = 1/100]\n", + " [With 8 bits]: 0.65 ~ 0.648438 (166 / 2^8) [error = 0/100]\n", + "\n", + " [With 2 bits]: 0.35 ~ 0.375 (3 / 2^3) [error = 7/100]\n", + " [With 4 bits]: 0.35 ~ 0.34375 (11 / 2^5) [error = 2/100]\n", + " [With 6 bits]: 0.35 ~ 0.351562 (45 / 2^7) [error = 0/100]\n", + " [With 8 bits]: 0.35 ~ 0.349609 (179 / 2^9) [error = 0/100]\n", + "\n", + " [With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965\n", + " [With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448\n", + " [With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008\n", + " [With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857\n", + " [With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967\n", + " [With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004\n", + " [With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977\n", + " [With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### __EXERCICE 10: print error in `display_sum()`__\n", + "\n", + "Modify slightly the function defined above to add display of the error; we will express it over 1000 (see exercice 7 which was roughly the same!)\n", + "\n", + "_Expected result_:\n", + "\n", + "````\n", + "[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 15/100]\n", + "[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 4/100]\n", + "[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 1/100]\n", + "[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 0/100]\n", + "\n", + "[With 2 bits]: 0.35 ~ 0.375 (3/2^3) [error = 7/100]\n", + "[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 2/100]\n", + "[With 6 bits]: 0.35 ~ 0.351562 (45/2^7) [error = 0/100]\n", + "[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 0/100]\n", + "\n", + "[With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965 [error = 254/1000]\n", + "[With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448 [error = 119/1000]\n", + "[With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008 [error = 8/1000]\n", + "[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 30/1000]\n", + "[With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967 [error = 2/1000]\n", + "[With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004 [error = 7/1000]\n", + "[With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977 [error = 0/1000]\n", + "[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2/1000]\n", + "````\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [optional] EXERCICE 11: function pointers\n", + "\n", + "Create a `loop()` function that takes as an argument :\n", + "\n", + "* An initial number of bits\n", + "* A final number of bits\n", + "* An increment to be applied to the number of bits\n", + "* A pointer to a function to be executed for each number of bits\n", + "\n", + "You will need the following intermediate function to be able to use them in `loop()` (as a specific signature is expected):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "void display_065(int Nbits)\n", + "{ \n", + " display_power_of_2_approx(Nbits, 0.65); \n", + "}\n", + "\n", + "void display_035(int Nbits)\n", + "{\n", + " display_power_of_2_approx(Nbits, 0.35); \n", + "}\n", + "\n", + "void display_065_3515_035_4832(int Nbits)\n", + "{ \n", + " display_sum(Nbits, 0.65, 3515, 0.35, 4832); \n", + "}\n", + "\n", + "int main()\n", + "{\n", + " loop(2, 8, 2, display_065);\n", + " loop(2, 8, 2, display_035);\n", + " loop(1, 8, 1, display_065_3515_035_4832);\n", + " return EXIT_SUCCESS;\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [optional] EXERCICE 12: write in output file \n", "\n", "Modify the program so that the `displayXXX` functions take an additional argument: the output stream to which the content should be written. `loop()` will be modified as well.\n", "\n", diff --git a/TP/1-ProceduralProgramming/CMakeLists.txt b/TP/1-ProceduralProgramming/CMakeLists.txt index 68b573f7cfa4960df15dd8c19feb2eb4b72035fa..12ac830f8551473358ae5ee9ce5de510c4386731 100644 --- a/TP/1-ProceduralProgramming/CMakeLists.txt +++ b/TP/1-ProceduralProgramming/CMakeLists.txt @@ -22,20 +22,33 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() - set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ compiler") set(CMAKE_C_COMPILER clang CACHE STRING "C compiler") set(CMAKE_CXX_STANDARD 17 CACHE INTEGER "Version of the C++ standard to use") set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "If ON the GNU version of the standard is used.") - + project(GettingStartedWithModernCpp_TP_Procedural) + +# Option to color the outputs with ninja. +# Adapted from https://medium.com/@alasher/colored-c-compiler-output-with-ninja-clang-gcc-10bfe7f2b949 +option (FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." True) + +if (${FORCE_COLORED_OUTPUT}) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + add_compile_options (-fdiagnostics-color=always) + elseif (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")) + add_compile_options (-fcolor-diagnostics) + endif () +endif () + 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("-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-missing-prototypes") # For this TP we will not separate declarations and definitions add_executable(initial initial_file.cpp) diff --git a/TP/1-ProceduralProgramming/Solution/exercice1.cpp b/TP/1-ProceduralProgramming/Solution/exercice1.cpp index bcc9423f964b5a94b7200544f3ecc52c1d4a57c8..3dbb0ce18f6954bb9b1e08fd015236c03db0a1a0 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice1.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice1.cpp @@ -1,46 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - - -/************************************/ -// 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 - - for (int i = 1; i <= 8; ++i) - { - int numerator = round_as_int(0.65 * times_power_of_2(1, i)); - std::cout << "0.65 ~ " << numerator << " / 2^" << i << std::endl ; - } - - std::cout << std::endl ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -56,11 +18,33 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } + +/************************************/ +// 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 + + for (int exponent = 1; exponent < 9; ++exponent) + { + int numerator = round_as_int(0.65 * times_power_of_2(1, exponent)); + std::cout << "0.65 ~ " << numerator << " / 2^" << exponent << std::endl; + } + + std::cout << std::endl; + + return EXIT_SUCCESS; +} + diff --git a/TP/1-ProceduralProgramming/Solution/exercice10.cpp b/TP/1-ProceduralProgramming/Solution/exercice10.cpp index 0bd45a4aafc6abf9d44545a2acf68311e5500747..cd4e8d155cab11717eee33c3042447e84e72bf9d 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice10.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice10.cpp @@ -1,84 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - - -/*! - * \brief Multiply an approximate representation of a double by an integer. - * - * \param[in] Nbits Number of bits available to represent `value` with the integer representation. - * \param[in] value Floating point value which is approximated by the integer representation. - * \param[in] coefficient Integer coefficient by which `value` is multiplied. - * - * \return An approximate integer result of the multiplication. - */ -int multiply(int Nbits, double value, int coefficient); - - -/*! - * \brief Display the approximate result of value1 * coefficient1 + value2 * coefficient2 computed with - * precision of `Nbits`. - */ -void display_sum(int Nbits, double value1, int coefficient1, double value2, int coefficient2); - - -// Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - - -/************************************/ -// 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 - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.65) ; - - std::cout << std::endl; - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.35) ; - - std::cout << std::endl; - - for (int Nbits = 1; Nbits <= 8; ++Nbits) - display_sum(Nbits, 0.65, 3515, 0.35, 4832); - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -94,76 +18,120 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - int error = round_as_int(100. * std::fabs(value - approx) / value); - - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' - << " [error = " << error << "/" << "100]" - << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; } +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + const double error = std::fabs(value - approx) / value; + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ") [error = " << round_as_int(100. * error) << "/100]" << std::endl; +} + + + +//! Multiply an approximated value by an integer. int multiply(int Nbits, double value, int coefficient) { int numerator {}, exponent {}; compute_power_of_2_approx(Nbits, value, numerator, exponent); - + return times_power_of_2(numerator * coefficient, -exponent); } -void display_sum(int Nbits, double value1, int coefficient1, double value2, int coefficient2) +//! Compute value1 * coefficient1 + value2 * coefficient2 over Nbits bits. +void display_multiply(int Nbits, double value1, int coefficient1, double value2, int coefficient2) { double exact = value1 * coefficient1 + value2 * coefficient2; int rounded = round_as_int(exact); int approx = multiply(Nbits, value1, coefficient1) + multiply(Nbits, value2, coefficient2); - int error = round_as_int(1000. * std::fabs(exact - approx) / exact); + const double error = std::fabs(exact - approx) / exact; std::cout << "[With " << Nbits << " bits]: " << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = " << rounded << " ~ " << approx - << " [error = " << error << "/" << "1000]" - << std::endl; + << " [error = " << round_as_int(1000. * error) << "/1000]" << std::endl; } -int max_int(int Nbits) -{ - return (times_power_of_2(1, Nbits) - 1); +/************************************/ +// 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 + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.65); + + std::cout << std::endl; + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.35); + + std::cout << std::endl; + + for (int Nbits = 1; Nbits <= 8; ++Nbits) + display_multiply(Nbits, 0.65, 3515, 0.35, 4832); // to compute 0.65 * 3515 + 0.35 * 4832 + + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/Solution/exercice11.cpp b/TP/1-ProceduralProgramming/Solution/exercice11.cpp index abd16c12409d304d56b1e1ec96dd42c4a3711545..f548416a595f117e7340d6c909bd43924b717521 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice11.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice11.cpp @@ -1,87 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - - -/*! - * \brief Multiply an approximate representation of a double by an integer. - * - * \param[in] Nbits Number of bits available to represent `value` with the integer representation. - * \param[in] value Floating point value which is approximated by the integer representation. - * \param[in] coefficient Integer coefficient by which `value` is multiplied. - * - * \return An approximate integer result of the multiplication. - */ -int multiply(int Nbits, double value, int coefficient); - - -/*! - * \brief Display the approximate result of value1 * coefficient1 + value2 * coefficient2 computed with - * precision of `Nbits`. - */ -void display_sum(int Nbits, double value1, int coefficient1, double value2, int coefficient2); - - -//! Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - -//! Loop over the number of bits from `initial` to `final` with `increment` and apply everytime `function`. -void loop(int initial, int final, int increment, void (*function) (int)); - -//! Wrapper to be able to pass the function to `loop()`. -void display_065(int Nbits); - -//! Wrapper to be able to pass the function to `loop()`. -void display_035(int Nbits); - -//! Wrapper to be able to pass the function to `loop()`. -void display_065_3515_035_4832(int Nbits); - - -/************************************/ -// 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 - - loop(2, 8, 2, display_065) ; - loop(2, 8, 2, display_035) ; - loop(1, 8, 1, display_065_3515_035_4832) ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -97,103 +18,134 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - int error = round_as_int(100. * std::fabs(value - approx) / value); - - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' - << " [error = " << error << "/" << "100]" - << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; } +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + const double error = std::fabs(value - approx) / value; + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ") [error = " << round_as_int(100. * error) << "/100]" << std::endl; +} + + + +//! Multiply an approximated value by an integer. int multiply(int Nbits, double value, int coefficient) { int numerator {}, exponent {}; compute_power_of_2_approx(Nbits, value, numerator, exponent); - + return times_power_of_2(numerator * coefficient, -exponent); } -void display_sum(int Nbits, double value1, int coefficient1, double value2, int coefficient2) +//! Compute value1 * coefficient1 + value2 * coefficient2 over Nbits bits. +void display_multiply(int Nbits, double value1, int coefficient1, double value2, int coefficient2) { double exact = value1 * coefficient1 + value2 * coefficient2; int rounded = round_as_int(exact); int approx = multiply(Nbits, value1, coefficient1) + multiply(Nbits, value2, coefficient2); - int error = round_as_int(1000. * std::fabs(exact - approx) / exact); + const double error = std::fabs(exact - approx) / exact; std::cout << "[With " << Nbits << " bits]: " << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = " << rounded << " ~ " << approx - << " [error = " << error << "/" << "1000]" - << std::endl; + << " [error = " << round_as_int(1000. * error) << "/1000]" << std::endl; } -int max_int(int Nbits) +void display_065(int Nbits) { - return (times_power_of_2(1, Nbits) - 1); + display_power_of_2_approx(Nbits, 0.65); } - -void loop(int initial, int final, int increment, void (*function) (int)) +void display_035(int Nbits) { - for (int Nbits = initial; Nbits <= final; Nbits += increment) - function(Nbits); - - std::cout << std::endl; + display_power_of_2_approx(Nbits, 0.35); } - -void display_065(int Nbits) +void display_065_3515_035_4832(int Nbits) { - display_power_of_2_approx(Nbits, 0.65); + display_multiply(Nbits, 0.65, 3515, 0.35, 4832); } - -void display_035(int Nbits) +void loop(int initial, int final, int increment, void(*display_function)(int)) { - display_power_of_2_approx(Nbits, 0.35); + for (int bits = initial; bits <= final; bits += increment) + display_function(bits); + + std::cout << std::endl; } -void display_065_3515_035_4832(int Nbits) -{ - display_sum(Nbits, 0.65, 3515, 0.35, 4832); +/************************************/ +// 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 + + loop(2, 8, 2, display_065); + loop(2, 8, 2, display_035); + loop(1, 8, 1, display_065_3515_035_4832); + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/Solution/exercice12.cpp b/TP/1-ProceduralProgramming/Solution/exercice12.cpp index b71fdd51b5827d315cb7aa81789204333908b880..1e029c61d8d4a3f6b4d735e3d18219fee3bd60e0 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice12.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice12.cpp @@ -1,97 +1,9 @@ #include <iostream> +#include <fstream> #include <cmath> // for std::round -#include <fstream> // for std::ofstream - - -/************************************/ -// Declarations -/************************************/ //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(std::ostream& out, int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - - -/*! - * \brief Multiply an approximate representation of a double by an integer. - * - * \param[in] Nbits Number of bits available to represent `value` with the integer representation. - * \param[in] value Floating point value which is approximated by the integer representation. - * \param[in] coefficient Integer coefficient by which `value` is multiplied. - * - * \return An approximate integer result of the multiplication. - */ -int multiply(int Nbits, double value, int coefficient); - - -/*! - * \brief Display the approximate result of value1 * coefficient1 + value2 * coefficient2 computed with - * precision of `Nbits`. - */ -void display_sum(std::ostream& out, int Nbits, double value1, int coefficient1, double value2, int coefficient2); - - -//! Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - -//! Loop over the number of bits from `initial` to `final` with `increment` and apply everytime `function`. -//! \param[in,out] out The output stream onto which the `function` will add content. -void loop(std::ostream& out, int initial, int final, int increment, void (*function) (std::ostream&, int)); - -//! Wrapper to be able to pass the function to `loop()`. -void display_065(std::ostream& out, int Nbits); - -//! Wrapper to be able to pass the function to `loop()`. -void display_035(std::ostream& out, int Nbits); - -//! Wrapper to be able to pass the function to `loop()`. -void display_065_3515_035_4832(std::ostream& out, int Nbits); - - -/************************************/ -// Main function -/************************************/ - -int main(int argc, char** argv) -{ - if (argc != 2) - { - std::cerr << "Two arguments are expected on command line: the name of the program followed by the " - "path of the file in which some of the outputs will be written." << std::endl; - exit(EXIT_FAILURE); - } - - // Open the stream to the file. - std::ofstream output_file(argv[1]); - - loop(output_file, 2, 8, 2, display_065); - loop(output_file, 2, 8, 2, display_035); - loop(std::cout, 1, 8, 1, display_065_3515_035_4832); - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -107,103 +19,144 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(std::ostream& out, int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - int error = round_as_int(100. * std::fabs(value - approx) / value); - - out << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' - << " [error = " << error << "/" << "100]" - << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; +} + + +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(std::ostream& out, int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + const double error = std::fabs(value - approx) / value; + + out << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ") [error = " << round_as_int(100. * error) << "/100]" << std::endl; } + +//! Multiply an approximated value by an integer. int multiply(int Nbits, double value, int coefficient) { int numerator {}, exponent {}; compute_power_of_2_approx(Nbits, value, numerator, exponent); - + return times_power_of_2(numerator * coefficient, -exponent); } -void display_sum(std::ostream& out, int Nbits, double value1, int coefficient1, double value2, int coefficient2) +//! Compute value1 * coefficient1 + value2 * coefficient2 over Nbits bits. +void display_multiply(std::ostream& out, int Nbits, double value1, int coefficient1, double value2, int coefficient2) { double exact = value1 * coefficient1 + value2 * coefficient2; int rounded = round_as_int(exact); int approx = multiply(Nbits, value1, coefficient1) + multiply(Nbits, value2, coefficient2); - int error = round_as_int(1000. * std::fabs(exact - approx) / exact); + const double error = std::fabs(exact - approx) / exact; out << "[With " << Nbits << " bits]: " << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = " << rounded << " ~ " << approx - << " [error = " << error << "/" << "1000]" - << std::endl; + << " [error = " << round_as_int(1000. * error) << "/1000]" << std::endl; } -int max_int(int Nbits) +void display_065(std::ostream& out, int Nbits) { - return (times_power_of_2(1, Nbits) - 1); + display_power_of_2_approx(out, Nbits, 0.65); } - -void loop(std::ostream& out, int initial, int final, int increment, void (*function) (std::ostream&, int)) +void display_035(std::ostream& out, int Nbits) { - for (int Nbits = initial; Nbits <= final; Nbits += increment) - function(out, Nbits); - - out << std::endl; + display_power_of_2_approx(out, Nbits, 0.35); } - -void display_065(std::ostream& out, int Nbits) +void display_065_3515_035_4832(std::ostream& out, int Nbits) { - display_power_of_2_approx(out, Nbits, 0.65); + display_multiply(out, Nbits, 0.65, 3515, 0.35, 4832); } - -void display_035(std::ostream& out, int Nbits) +void loop(std::ostream& out, int initial, int final, int increment, void(*display_function)(std::ostream&, int)) { - display_power_of_2_approx(out, Nbits, 0.35); + for (int bits = initial; bits <= final; bits += increment) + display_function(out, bits); + + out << std::endl; } -void display_065_3515_035_4832(std::ostream& out, int Nbits) -{ - display_sum(out, Nbits, 0.65, 3515, 0.35, 4832); +/************************************/ +// 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 + + if (argc != 2) + { + std::cerr << "Two arguments are expected on command line: the name of the program followed by the " + "path of the file in which some of the outputs will be written." << std::endl; + exit(EXIT_FAILURE); + } + + // Open the stream to the file. + std::ofstream output_file(argv[1]); + + loop(output_file, 2, 8, 2, display_065); + loop(output_file, 2, 8, 2, display_035); + loop(std::cout, 1, 8, 1, display_065_3515_035_4832); + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/Solution/exercice2.cpp b/TP/1-ProceduralProgramming/Solution/exercice2.cpp index aaee379dcaed383ab9678a6421bbfffb9e53957a..c1959f44bcbe7c3cbd6e9f7e119dfe01b78a3741 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice2.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice2.cpp @@ -1,44 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation. -void display_power_of_2_approx(double value); - - -/************************************/ -// 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 - - display_power_of_2_approx(0.65); - display_power_of_2_approx(0.35); - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -54,21 +18,42 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } +//! Display the approximation of the given argument for the exponents from 1 to 8. void display_power_of_2_approx(double value) { - for (int i = 1; i <= 8; ++i) + for (int exponent = 1; exponent <= 8; ++exponent) { - int numerator = round_as_int(value * times_power_of_2(1, i)); - std::cout << value << " ~ " << numerator << " / 2^" << i << std::endl ; - } + int numerator = round_as_int(value * times_power_of_2(1, exponent)); + std::cout << value << " ~ " << numerator << " / 2^" << exponent << std::endl; + } + std::cout << std::endl; + +} + + + +/************************************/ +// Main function +/************************************/ + +int main(int argc, char** argv) +{ + static_cast<void>(argc); // to silence warning about unused argc - don't bother + static_cast<void>(argv); // to silence warning about unused argv - don't bother + + display_power_of_2_approx(.65); + display_power_of_2_approx(.35); + + return EXIT_SUCCESS; } diff --git a/TP/1-ProceduralProgramming/Solution/exercice3.cpp b/TP/1-ProceduralProgramming/Solution/exercice3.cpp index 4137a92d59d697affa2ab5c6ae0a61679334d989..57b5321bc1e8c7c06f529effcda4ab78e11cdac4 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice3.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice3.cpp @@ -1,44 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation. -void display_power_of_2_approx(double value); - - -/************************************/ -// 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 - - display_power_of_2_approx(0.65); - display_power_of_2_approx(0.35); - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -54,25 +18,46 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } +//! Display the approximation of the given argument for the exponents from 1 to 8. void display_power_of_2_approx(double value) { for (int exponent = 1; exponent <= 8; ++exponent) { int denominator = times_power_of_2(1, exponent); int numerator = round_as_int(value * denominator); - double approx = static_cast<double>(numerator) / denominator; + double approx = static_cast<double>(numerator) / denominator; - std::cout << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' << std::endl; - } + std::cout << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ')' << std::endl; + } std::cout << std::endl; + +} + + + +/************************************/ +// Main function +/************************************/ + +int main(int argc, char** argv) +{ + static_cast<void>(argc); // to silence warning about unused argc - don't bother + static_cast<void>(argv); // to silence warning about unused argv - don't bother + + display_power_of_2_approx(.65); + display_power_of_2_approx(.35); + + return EXIT_SUCCESS; } diff --git a/TP/1-ProceduralProgramming/Solution/exercice4.cpp b/TP/1-ProceduralProgramming/Solution/exercice4.cpp index fb0b4300fb5694e53e0d8d4366e09bbf67901c12..5dbb9674807f2ce1bb656e49e63d098664271e14 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice4.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice4.cpp @@ -1,48 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator lesser than `max_numerator`. -void display_power_of_2_approx(int max_numerator, double value); - - -/************************************/ -// 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 - - display_power_of_2_approx(15, 0.65) ; - display_power_of_2_approx(255, 0.65) ; - - display_power_of_2_approx(15, 0.35) ; - display_power_of_2_approx(255, 0.35) ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -58,33 +18,62 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_display_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) +{ + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +//! Display the approximation of the given argument that does not exceed the chosen maximum numerator. void display_power_of_2_approx(int max_numerator, double value) { - int exponent {}; - int numerator {}, denominator {}; + int numerator {}, denominator{}, exponent {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_display_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); - double approx = static_cast<double>(numerator) / denominator; + helper_display_power_of_2_approx(value, --exponent, numerator, denominator); - std::cout << "[With numerator < " << max_numerator << "]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' << std::endl ; + double approx = static_cast<double>(numerator) / denominator; + + std::cout << "[With numerator <= "<< max_numerator << "]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ')' << std::endl; +} + + + +/************************************/ +// Main function +/************************************/ + +int main(int argc, char** argv) +{ + static_cast<void>(argc); // to silence warning about unused argc - don't bother + static_cast<void>(argv); // to silence warning about unused argv - don't bother + + display_power_of_2_approx(15, 0.65); + display_power_of_2_approx(255, 0.65); + + display_power_of_2_approx(15, 0.35); + display_power_of_2_approx(255, 0.35); + + return EXIT_SUCCESS; } diff --git a/TP/1-ProceduralProgramming/Solution/exercice5.cpp b/TP/1-ProceduralProgramming/Solution/exercice5.cpp index f0772437a2233e77e4220c2e2c15c990aed6c8b1..77333673b9b840563a7dae27f66e25593739731e 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice5.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice5.cpp @@ -1,53 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - -// Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - - -/************************************/ -// 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 - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.65) ; - - std::cout << std::endl; - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.35) ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -63,40 +18,72 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_display_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) +{ + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); +} + + +//! Display the approximation of the given argument that fits in the given number of bits. void display_power_of_2_approx(int Nbits, double value) { - int exponent {}; - int numerator {}, denominator {}; - int max_numerator = max_int(Nbits); + int numerator {}, denominator{}, exponent {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_display_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); - double approx = static_cast<double>(numerator) / denominator; + helper_display_power_of_2_approx(value, --exponent, numerator, denominator); - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' << std::endl ; + double approx = static_cast<double>(numerator) / denominator; + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ')' << std::endl; } -int max_int(int Nbits) -{ - return (times_power_of_2(1, Nbits) - 1); + +/************************************/ +// 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 + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.65) ; + + std::cout << std::endl; + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.35) ; + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/Solution/exercice6.cpp b/TP/1-ProceduralProgramming/Solution/exercice6.cpp index 74b7cce574ad821ee614749a6c372582cd3af305..b7797bf063aceae0f8da5a3c53e93d60cfaedca8 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice6.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice6.cpp @@ -1,59 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - -// Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - - -/************************************/ -// 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 - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.65) ; - - std::cout << std::endl; - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.35) ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -69,48 +18,86 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; } -int max_int(int Nbits) -{ - return (times_power_of_2(1, Nbits) - 1); +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ')' << std::endl; } + + + +/************************************/ +// Main function +/************************************/ + +int main(int argc, char** argv) +{ + static_cast<void>(argc); // to silence warning about unused argc - don't bother + static_cast<void>(argv); // to silence warning about unused argv - don't bother + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.65) ; + + std::cout << std::endl; + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.35) ; + + return EXIT_SUCCESS; +} + diff --git a/TP/1-ProceduralProgramming/Solution/exercice7.cpp b/TP/1-ProceduralProgramming/Solution/exercice7.cpp index 6c2f61b82792d8af8a7c315eda46cc329cca1358..93aca818dcc8782dcffd021a26ed402890694cfa 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice7.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice7.cpp @@ -1,59 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - -// Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - - -/************************************/ -// 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 - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.65) ; - - std::cout << std::endl; - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.35) ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -69,51 +18,88 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - int error = round_as_int(100. * std::fabs(value - approx) / value); - - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' - << " [error = " << error << "/" << "100]" - << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; } -int max_int(int Nbits) -{ - return (times_power_of_2(1, Nbits) - 1); +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + const double error = std::fabs(value - approx) / value; + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ") [error = " << round_as_int(100. * error) << "/100]" << std::endl; +} + + + +/************************************/ +// Main function +/************************************/ + +int main(int argc, char** argv) +{ + static_cast<void>(argc); // to silence warning about unused argc - don't bother + static_cast<void>(argv); // to silence warning about unused argv - don't bother + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.65) ; + + std::cout << std::endl; + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.35) ; + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/Solution/exercice8.cpp b/TP/1-ProceduralProgramming/Solution/exercice8.cpp index fa2cfbdeb77e8a2f05e9cbd55eef308c3df7f3ce..ae29fca93fea23251ae5dc9029557ccb06703332 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice8.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice8.cpp @@ -1,83 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - - -/*! - * \brief Multiply an approximate representation of a double by an integer. - * - * \param[in] Nbits Number of bits available to represent `value` with the integer representation. - * \param[in] value Floating point value which is approximated by the integer representation. - * \param[in] coefficient Integer coefficient by which `value` is multiplied. - * - * \return An approximate integer result of the multiplication. - */ -int multiply(int Nbits, double value, int coefficient); - - -// Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - - -/************************************/ -// 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 - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.65) ; - - std::cout << std::endl; - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.35) ; - - std::cout << std::endl; - - for (int Nbits = 1; Nbits <= 8; ++Nbits) - { - double exact = 0.65 * 3515 + 0.35 * 4832; - int rounded = round_as_int(exact); - int approx = multiply(Nbits, 0.65, 3515) + multiply(Nbits, 0.35, 4832); - std::cout << "[With " << Nbits << " bits]: 0.65 * 3515 + 0.35 * 4832 = " - << rounded << " ~ " << approx << std::endl; - } - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -93,60 +18,109 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - int error = round_as_int(100. * std::fabs(value - approx) / value); - - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' - << " [error = " << error << "/" << "100]" - << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; +} + + +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + const double error = std::fabs(value - approx) / value; + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ") [error = " << round_as_int(100. * error) << "/100]" << std::endl; } + +//! Multiply an approximated value by an integer. int multiply(int Nbits, double value, int coefficient) { int numerator {}, exponent {}; compute_power_of_2_approx(Nbits, value, numerator, exponent); - + return times_power_of_2(numerator * coefficient, -exponent); } -int max_int(int Nbits) -{ - return (times_power_of_2(1, Nbits) - 1); +/************************************/ +// 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 + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.65); + + std::cout << std::endl; + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.35); + + std::cout << std::endl; + + for (int Nbits = 1; Nbits <= 8; ++Nbits) + { + double exact = 0.65 * 3515; + int rounded = round_as_int(exact); + int approx = multiply(Nbits, 0.65, 3515); + std::cout << "[With " << Nbits << " bits]: 0.65 * 3515 = " + << rounded << " ~ " << approx << std::endl; + } + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/Solution/exercice9.cpp b/TP/1-ProceduralProgramming/Solution/exercice9.cpp index 103f1ac314b82369505af7437ae5d4ff78de98c1..af49ff4f158ea1c7482df1b93ba030d8aa255863 100644 --- a/TP/1-ProceduralProgramming/Solution/exercice9.cpp +++ b/TP/1-ProceduralProgramming/Solution/exercice9.cpp @@ -1,84 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - -//! Display the approximation of `value` in the proposed representation with the highest possible -//! numerator that may be represented in `Nbits` bits. -void display_power_of_2_approx(int Nbits, double value); - - -//! Compute the best possible approximation of `value` with `Nbits` -//! \param[out] numerator Computed numerator. -//! \param[out] exponent Computed exponent. -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent); - - -/*! - * \brief Multiply an approximate representation of a double by an integer. - * - * \param[in] Nbits Number of bits available to represent `value` with the integer representation. - * \param[in] value Floating point value which is approximated by the integer representation. - * \param[in] coefficient Integer coefficient by which `value` is multiplied. - * - * \return An approximate integer result of the multiplication. - */ -int multiply(int Nbits, double value, int coefficient); - - -/*! - * \brief Display the approximate result of value1 * coefficient1 + value2 * coefficient2 computed with - * precision of `Nbits`. - */ -void display_sum(int Nbits, double value1, int coefficient1, double value2, int coefficient2); - - -// Maximum integer that might be represented with `Nbits` bits. -int max_int(int Nbits); - - -/************************************/ -// 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 - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.65) ; - - std::cout << std::endl; - - for (int Nbits = 2; Nbits <= 8; Nbits += 2) - display_power_of_2_approx(Nbits, 0.35) ; - - std::cout << std::endl; - - for (int Nbits = 1; Nbits <= 8; ++Nbits) - display_sum(Nbits, 0.65, 3515, 0.35, 4832); - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -94,60 +18,83 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } -void display_power_of_2_approx(int Nbits, double value) +// Maximum integer that might be represented with `Nbits` bits. +int max_int(int Nbits) +{ + return (times_power_of_2(1, Nbits) - 1); +} + + +//! Helper function that computes numerator and denominator. +//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle! +void helper_compute_power_of_2_approx(double value, int exponent, int& numerator, int& denominator) { - int numerator {}, exponent {}; - compute_power_of_2_approx(Nbits, value, numerator, exponent); - int denominator = times_power_of_2(1, exponent); - double approx = static_cast<double>(numerator) / denominator; - int error = round_as_int(100. * std::fabs(value - approx) / value); - - std::cout << "[With " << Nbits << " bits]: " - << value << " ~ " << approx << " (" << numerator << "/2^" << exponent << ')' - << " [error = " << error << "/" << "100]" - << std::endl ; + denominator = times_power_of_2(1, exponent); + numerator = round_as_int(value * denominator); } -void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) + +//! Compute the best possible approximation of `value` with `Nbits` +//! \param[out] numerator Computed numerator. +//! \param[out] exponent Computed exponent. +//! \return The approximation as a floating point. +double compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent) { - numerator = exponent = 0; - int denominator {}; - int max_numerator = max_int(Nbits); + numerator = 0; + exponent = 0; + int denominator {}; do { - ++exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + // I used here the preffix increment '++exponent' but you may put it on a separate line if you're not + // comfortable with it. + helper_compute_power_of_2_approx(value, ++exponent, numerator, denominator); } while (numerator <= max_numerator); - --exponent; - denominator = times_power_of_2(1, exponent); - numerator = round_as_int(value * denominator); + helper_compute_power_of_2_approx(value, --exponent, numerator, denominator); + + return static_cast<double>(numerator) / denominator; } +//! Display the approximation of the given argument that fits in the given number of bits. +void display_power_of_2_approx(int Nbits, double value) +{ + int numerator {}, exponent {}; + const double approx = compute_power_of_2_approx(Nbits, value, numerator, exponent); + + const double error = std::fabs(value - approx) / value; + + std::cout << "[With " << Nbits << " bits]: " << value << " ~ " << approx << " (" << numerator << + " / 2^" << exponent << ") [error = " << round_as_int(100. * error) << "/100]" << std::endl; +} + + + +//! Multiply an approximated value by an integer. int multiply(int Nbits, double value, int coefficient) { int numerator {}, exponent {}; compute_power_of_2_approx(Nbits, value, numerator, exponent); - + return times_power_of_2(numerator * coefficient, -exponent); } -void display_sum(int Nbits, double value1, int coefficient1, double value2, int coefficient2) +//! Compute value1 * coefficient1 + value2 * coefficient2 over Nbits bits. +void display_multiply(int Nbits, double value1, int coefficient1, double value2, int coefficient2) { double exact = value1 * coefficient1 + value2 * coefficient2; int rounded = round_as_int(exact); @@ -158,7 +105,29 @@ void display_sum(int Nbits, double value1, int coefficient1, double value2, int } -int max_int(int Nbits) -{ - return (times_power_of_2(1, Nbits) - 1); +/************************************/ +// 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 + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.65); + + std::cout << std::endl; + + for (int Nbits = 2; Nbits <= 8; Nbits += 2) + display_power_of_2_approx(Nbits, 0.35); + + std::cout << std::endl; + + for (int Nbits = 1; Nbits <= 8; ++Nbits) + display_multiply(Nbits, 0.65, 3515, 0.35, 4832); // to compute 0.65 * 3515 + 0.35 * 4832 + + + return EXIT_SUCCESS; } + diff --git a/TP/1-ProceduralProgramming/initial_file.cpp b/TP/1-ProceduralProgramming/initial_file.cpp index 6f843620e7040ec5764395ce94d93f23a215f20b..2139f26b81787d9d49499b0bef1416c0190489d7 100644 --- a/TP/1-ProceduralProgramming/initial_file.cpp +++ b/TP/1-ProceduralProgramming/initial_file.cpp @@ -1,49 +1,8 @@ #include <iostream> #include <cmath> // for std::round -/************************************/ -// Declarations -/************************************/ - //! 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); - - - -/************************************/ -// 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 - - int num1 = round_as_int(0.65 * times_power_of_2(1, 1)); - std::cout << "0.65 ~ " << num1 << " / 2^1" << std::endl ; - - int num2 = round_as_int(0.65 * times_power_of_2(1, 2)); - std::cout << "0.65 ~ " << num2 << " / 2^2" << std::endl ; - - int num3 = round_as_int(0.65 * times_power_of_2(1, 3)); - std::cout << "0.65 ~ " << num3 << " / 2^3" << std::endl ; - - std::cout << std::endl ; - - return EXIT_SUCCESS; -} - - -/************************************/ -// Definitions -/************************************/ - - int times_power_of_2(int number, int exponent) { while (exponent > 0) @@ -59,11 +18,36 @@ int times_power_of_2(int number, int exponent) return number; } + - +//! Round to `x` the nearest integer. int round_as_int(double x) { return static_cast<int>(std::round(x)); } + +/************************************/ +// 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 + + int numerator1 = round_as_int(0.65 * times_power_of_2(1, 1)); + std::cout << "0.65 ~ " << numerator1 << " / 2^1" << std::endl ; + + int numerator2 = round_as_int(0.65 * times_power_of_2(1, 2)); + std::cout << "0.65 ~ " << numerator2 << " / 2^2" << std::endl ; + + int numerator3 = round_as_int(0.65 * times_power_of_2(1, 3)); + std::cout << "0.65 ~ " << numerator3 << " / 2^3" << std::endl ; + + std::cout << std::endl ; + + return EXIT_SUCCESS; +} +