Commit 8cc12de3 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Refactoring of the TPs related to procedural programming; they have been...

Refactoring of the TPs related to procedural programming; they have been located directly in a subfolder of the lecture directory.
parent 1733371f
This diff is collapsed.
This diff is collapsed.
......@@ -14,18 +14,18 @@
},
"source": [
"<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-11:-write-(possibly)-in-output-file\" data-toc-modified-id=\"EXERCICE-11:-write-(possibly)-in-output-file-1\">EXERCICE 11: write (possibly) in output file</a></span></li></ul></div>"
"<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>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 11: write (possibly) in output file \n",
"### 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.\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",
"The code should work with this `main()`:"
"The following `main()` which writes part of the outputs in a file should work:"
]
},
{
......@@ -34,66 +34,24 @@
"metadata": {},
"outputs": [],
"source": [
"int main(int argc, char** argv)\n",
"{\n",
" static_cast<void>(argc); // to silence diwarning 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(std::cout, 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(std::cout, 0.35, Nbits);\n",
" \n",
" std::cout << std::endl;\n",
" \n",
" for (int Nbits = 1; Nbits <= 8; ++Nbits)\n",
" display_multiply(std::cout, Nbits, 0.65, 3515, 0.35, 4832);\n",
" \n",
" return EXIT_SUCCESS;\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"but also this one:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#include <fstream> // for std::ofstream\n",
"#include <fstream>\n",
"\n",
"int main(int argc, char** argv)\n",
"{\n",
" if (argc != 2)\n",
" {\n",
" std::cerr << \"Exactly two arguments are expected on command line (program name included)!\" << std::endl;\n",
" exit(EXIT_FAILURE); \n",
" std::cerr << \"Two arguments are expected on command line: the name of the program followed by the \"\n",
" \"path of the file in which some of the outputs will be written.\" << std::endl;\n",
" exit(EXIT_FAILURE);\n",
" }\n",
" \n",
" std::ofstream out(argv[1]);\n",
" // Open the stream to the file.\n",
" std::ofstream output_file(argv[1]);\n",
" \n",
" for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n",
" display_power_of_2_approx(out, 0.65, Nbits);\n",
"\n",
" out << std::endl;\n",
" loop(output_file, 2, 8, 2, display_065);\n",
" loop(output_file, 2, 8, 2, display_035);\n",
" loop(std::cout, 1, 8, 1, display_065_3515_035_4832);\n",
"\n",
" for (int Nbits = 2; Nbits <= 8; Nbits += 2)\n",
" display_power_of_2_approx(out, 0.35, Nbits);\n",
" \n",
" out << std::endl;\n",
" \n",
" for (int Nbits = 1; Nbits <= 8; ++Nbits)\n",
" display_multiply(out, Nbits, 0.65, 3515, 0.35, 4832);\n",
" \n",
" return EXIT_SUCCESS;\n",
"}"
]
......
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [TP 1](/notebooks/1-ProceduralProgramming/7b-TP.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#EXERCICE-11:-write-(possibly)-in-output-file" data-toc-modified-id="EXERCICE-11:-write-(possibly)-in-output-file-1">EXERCICE 11: write (possibly) in output file</a></span></li></ul></div>
<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>
%% Cell type:markdown id: tags:
### EXERCICE 11: write (possibly) in output file
### EXERCICE 12: write in output file
Modify the program so that the `displayXXX` functions take an additional argument: the output stream to which the content should be written.
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.
The code should work with this `main()`:
The following `main()` which writes part of the outputs in a file should work:
%% Cell type:code id: tags:
``` C++17
int main(int argc, char** argv)
{
static_cast<void>(argc); // to silence diwarning 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(std::cout, 0.65, Nbits);
std::cout << std::endl;
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(std::cout, 0.35, Nbits);
std::cout << std::endl;
for (int Nbits = 1; Nbits <= 8; ++Nbits)
display_multiply(std::cout, Nbits, 0.65, 3515, 0.35, 4832);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
but also this one:
%% Cell type:code id: tags:
``` C++17
#include <fstream> // for std::ofstream
#include <fstream>
int main(int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "Exactly two arguments are expected on command line (program name included)!" << std::endl;
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);
}
std::ofstream out(argv[1]);
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(out, 0.65, Nbits);
out << std::endl;
for (int Nbits = 2; Nbits <= 8; Nbits += 2)
display_power_of_2_approx(out, 0.35, Nbits);
out << std::endl;
// Open the stream to the file.
std::ofstream output_file(argv[1]);
for (int Nbits = 1; Nbits <= 8; ++Nbits)
display_multiply(out, Nbits, 0.65, 3515, 0.35, 4832);
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;
}
```
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_
_This notebook is an adaptation of a lecture prepared and redacted by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
......@@ -15,11 +15,13 @@ endmacro()
# Don't do such hardcoding in a real project: you want to be able to supersede these settings on command line.
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER clang++ )
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
project(GettingStartedWithModernCppTP)
add_cxx_compiler_flag("-Weverything") # all warnings for clang
add_cxx_compiler_flag("-Wall") # for gcc (and recognized by clang)
......@@ -30,14 +32,15 @@ add_cxx_compiler_flag("-Wno-c++98-compat-pedantic") # We assume we are using mod
add_executable(initial initial_file.cpp)
# add_executable(exo1 exo1.cpp)
# add_executable(exo2 exo2.cpp)
# add_executable(exo3 exo3.cpp)
# add_executable(exo4 exo4.cpp)
# add_executable(exo5 exo5.cpp)
# add_executable(exo6 exo6.cpp)
# add_executable(exo7 exo7.cpp)
# add_executable(exo8 exo8.cpp)
# add_executable(exo9 exo9.cpp)
# add_executable(exo10 exo10.cpp)
# add_executable(exo11 exo11.cpp)
\ No newline at end of file
# add_executable(exercice1 exercice1.cpp)
# add_executable(exercice2 exercice2.cpp)
# add_executable(exercice3 exercice3.cpp)
# add_executable(exercice4 exercice4.cpp)
# add_executable(exercice5 exercice5.cpp)
# add_executable(exercice6 exercice6.cpp)
# add_executable(exercice7 exercice7.cpp)
# add_executable(exercice8 exercice8.cpp)
# add_executable(exercice9 exercice9.cpp)
# add_executable(exercice10 exercice10.cpp)
# add_executable(exercice11 exercice11.cpp)
# add_executable(exercice12 exercice12.cpp)
\ No newline at end of file
#include <iostream>
#include <cmath> // for std::round
/************************************/
// Declarations
/************************************/
//! Returns number * (2 ^ exponent) as an integer.
//! Returns `number` * (2 ^ `exponent`)
int times_power_of_2(int number, int exponent);
//! Round to the nearest integer.
//! Round to `x` the nearest integer.
int round_as_int(double x);
void display_power_of_2_approx(double number);
/************************************/
// 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);
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)
{
......@@ -49,12 +64,3 @@ int round_as_int(double x)
}
void display_power_of_2_approx(double number)
{
for (int i = 1; i < 9; ++i)
{
int rounded = round_as_int(number * times_power_of_2(1, i));
std::cout << number << " ~ " << rounded << " / 2^" << i << std::endl ;
}
std::cout << std::endl ;
}
#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)
{
number *= 2;
exponent -= 1;
}
while (exponent < 0)
{
number /= 2;
exponent += 1 ;
}
return number;
}
int round_as_int(double x)
{
return static_cast<int>(std::round(x));
}
void display_power_of_2_approx(int Nbits, double value)
{
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 << " ~ " << numerator << " / 2^" << exponent << " (" << approx << ')'
<< " [error = " << error << "/" << "100]"
<< std::endl ;
}
void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent)
{
numerator = exponent = 0;
int denominator {};
int max_numerator = max_int(Nbits);
do
{
++exponent;
denominator = times_power_of_2(1, exponent);
numerator = round_as_int(value * denominator);
}
while (numerator <= max_numerator);
--exponent;
denominator = times_power_of_2(1, exponent);
numerator = round_as_int(value * denominator);
}
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)
{
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);
std::cout << "[With " << Nbits << " bits]: " << value1 << " * " << coefficient1
<< " + " << value2 << " * " << coefficient2 << " = "
<< rounded << " ~ " << approx
<< " [error = " << error << "/" << "1000]"
<< std::endl;
}
int max_int(int Nbits)
{
return (times_power_of_2(1, Nbits) - 1);
}
#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)
{
number *= 2;
exponent -= 1;
}
while (exponent < 0)
{
number /= 2;
exponent += 1 ;
}
return number;
}
int round_as_int(double x)
{
return static_cast<int>(std::round(x));
}
void display_power_of_2_approx(int Nbits, double value)
{
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 << " ~ " << numerator << " / 2^" << exponent << " (" << approx << ')'
<< " [error = " << error << "/" << "100]"
<< std::endl ;
}
void compute_power_of_2_approx(int Nbits, double value, int& numerator, int& exponent)
{
numerator = exponent = 0;
int denominator {};
int max_numerator = max_int(Nbits);
do
{
++exponent;
denominator = times_power_of_2(1, exponent);
numerator = round_as_int(value * denominator);
}
while (numerator <= max_numerator);
--exponent;
denominator = times_power_of_2(1, exponent);
numerator = round_as_int(value * denominator);
}
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);