- Date de la séance de TD : vendredi 26 septembre 2025 - 10h00
1. Définition de fonctions, lecture de données et affichage
1.1. Définition d'une fonction simple, affichage
Nous allons nous intéresser à la fonction {$f(x) = sin(x)+cos(\sqrt{2}*x)$} ; nous souhaitons plus particulièrement trouver ses extrema. La voici sous forme graphique sur l'intervalle {$ [-10,10] $} :

- Définir une fonction de signature
double sin_x_plus_cos_sqrt2_times_x( double x );
qui calcule et retourne la valeur de {$f$} en {$x$}.
À partir de C++20, {$\sqrt{2}$} peut être obtenu avec std::numbers::sqrt2 (avec le fichier d'entête <numbers>).
Sinon, {$\sqrt{2}$} est définie comme constante nommée M_SQRT2 dans <cmath>.
- Définir une fonction
test_11()qui appelle la précédente avec1puis avec-4.5comme argument, et qui affiche les résultats retournés.
Appeler cette fonction dansmain(), le résultat attendu est :
sin_x_plus_cos_sqrt2_times_x( 1 ) = 0.997415sin_x_plus_cos_sqrt2_times_x( -4.5 ) = 1.97427
1.2. Lecture
- Définir une fonction
test_12()qui demande une valeur à l'utilisateur, appelle la fonctionsin_x_plus_cos_sqrt2_times_x()avec la valeur fournie par l'utilisateur comme argument et affiche le résultat retourné.
Appeler cette fonction dansmain(), voici un exemple du résultat attendu (en vert, ce qui est fourni par l'utilisateur) :
Valeur : -4.53sin_x_plus_cos_sqrt2_times_x( -4.53 ) = 1.97583
2. Structures de contrôle
2.1. Boucle for version 1
- Définir une fonction
test_21()qui demande une valeur à l'utilisateur, et affiche le résultat de l'appel de la fonctionsin_x_plus_cos_sqrt2_times_x()pour 10 valeurs espacées de 1 en commençant avec la valeur fournie par l'utilisateur.
Vous utiliserez une boucleforavec une variable de boucle commençant à0.
Appeler cette fonction dansmain(), voici un exemple du résultat attendu (en vert, ce qui est fourni par l'utilisateur) :
Valeur initiale : -5sin_x_plus_cos_sqrt2_times_x( -5 ) = 1.66427sin_x_plus_cos_sqrt2_times_x( -4 ) = 1.56699sin_x_plus_cos_sqrt2_times_x( -3 ) = -0.593782sin_x_plus_cos_sqrt2_times_x( -2 ) = -1.86066sin_x_plus_cos_sqrt2_times_x( -1 ) = -0.685527sin_x_plus_cos_sqrt2_times_x( 0 ) = 1sin_x_plus_cos_sqrt2_times_x( 1 ) = 0.997415sin_x_plus_cos_sqrt2_times_x( 2 ) = -0.0420657sin_x_plus_cos_sqrt2_times_x( 3 ) = -0.311542sin_x_plus_cos_sqrt2_times_x( 4 ) = 0.0533811
2.2. Boucle for version 2
- Définir une fonction de signature
void print_sin_x_plus_cos_sqrt2_times_x( double begin, double end, double step );
- qui affiche le résultat de la fonction
sin_x_plus_cos_sqrt2_times_x()pour toutes les valeurs entrebeginetendavec un pas destep.
Vous utiliserez une boucleforavec une variable de boucle commençant àbegin.
- Définir une fonction
test_22()qui appelle la précédente avec-10,10et2comme arguments. Appeler cette fonction dansmain(), le résultat attendu est :
sin_x_plus_cos_sqrt2_times_x( -10 ) = 0.539052sin_x_plus_cos_sqrt2_times_x( -8 ) = -0.676563sin_x_plus_cos_sqrt2_times_x( -6 ) = -0.310779sin_x_plus_cos_sqrt2_times_x( -4 ) = 1.56699sin_x_plus_cos_sqrt2_times_x( -2 ) = -1.86066sin_x_plus_cos_sqrt2_times_x( 0 ) = 1sin_x_plus_cos_sqrt2_times_x( 2 ) = -0.0420657sin_x_plus_cos_sqrt2_times_x( 4 ) = 0.0533811sin_x_plus_cos_sqrt2_times_x( 6 ) = -0.86961sin_x_plus_cos_sqrt2_times_x( 8 ) = 1.30215sin_x_plus_cos_sqrt2_times_x( 10 ) = -0.54899
2.3. Conditionnelle, boucle while
- Définir une fonction
test_23()qui demande à l'utilisateur une borne basse, une borne haute (qui devra être supérieure à la borne basse) et un nombre de valeurs à afficher, puis appelle la fonctionprint_sin_x_plus_cos_sqrt2_times_x()pour afficher les valeurs demandées.
Vous utiliserez une instructionifpour vérifier que la borne haute donnée par l'utilisateur est strictement supérieure à la borne basse, et une instructionwhileoudo .. whilepour refaire une demande en cas de test négatif ; vous ferez de même pour vérifier qu'au moins 2 valeurs sont demandées.
Appeler cette fonction dansmain(), voici un exemple du résultat attendu (en vert, ce qui est fourni par l'utilisateur) :
Borne basse : -2Borne haute : -4Erreur : la borne haute doit être plus grande que la borne basseBorne haute : 2Nombre de valeurs : 1Erreur : le nombre de valeurs doit être au minimum 2Nombre de valeurs : 11sin_x_plus_cos_sqrt2_times_x( -2 ) = -1.86066sin_x_plus_cos_sqrt2_times_x( -1.6 ) = -1.63761sin_x_plus_cos_sqrt2_times_x( -1.2 ) = -1.05796sin_x_plus_cos_sqrt2_times_x( -0.8 ) = -0.291936sin_x_plus_cos_sqrt2_times_x( -0.4 ) = 0.454803sin_x_plus_cos_sqrt2_times_x( -1.11022e-16 ) = 1sin_x_plus_cos_sqrt2_times_x( 0.4 ) = 1.23364sin_x_plus_cos_sqrt2_times_x( 0.8 ) = 1.14278sin_x_plus_cos_sqrt2_times_x( 1.2 ) = 0.806114sin_x_plus_cos_sqrt2_times_x( 1.6 ) = 0.361537sin_x_plus_cos_sqrt2_times_x( 2 ) = -0.0420657
Si vous entrez autre chose que des nombres lors de la lecture, votre programme risque de boucler de manière infinie et il faudra l'arrêter avec CTRL-C.
Le corrigé vous montrera comment faire en utilisant ignore(), mais il ne vous est pas demandé d'écrire ce traitement d'erreur.
3. Fonction comme argument
3.1. Calcul de dérivée
Pour trouver les extrema de notre fonction, nous allons chercher les points où sa dérivée s'annule. Nous souhaitons que notre recherche d'extrema soit générique et indépendante de la fonction étudiée, ce qui signifie que nous ne connaissons pas sa dérivée formelle. Nous allons donc utiliser un calcul approché de cette dérivée en utilisant la formule {$f'(x) ≃ \frac{f(x + ε) - f(x)}{ε}$}.
Une signature possible de notre fonction, calculant la valeur estimée de la dérivée de la fonction func en x, pourrait être :
double compute_derivative( double func( double ), double x, double epsilon );
Et nous pourrions alors l'utiliser ainsi :
double estimate = compute_derivative( sin_x_plus_cos_sqrt2_times_x, 1, 1e-5 );
Pour recevoir la fonction avec l'argument func, nous allons plutôt utiliser le type std::function de la bibliothèque standard qui est beaucoup plus général, ce qui sera nécessaire pour la suite ; cela ne changera rien à son utilisation.
- Définir une fonction de signature
double compute_derivative( std::function< double( double ) > func, double x, double epsilon );
- qui retourne la valeur estimée de la dérivée de la fonction
funcenx.
Les caractères < et > indiquent que le type std::function est générique ; entre ces deux symboles figure le paramètre de généricité : une fonction qui reçoit un double en argument et retourne un double. La généricité sera vue lors d'un cours ultérieur.
- Définir une fonction
test_31()qui affiche l'estimation de la dérivée desin_x_plus_cos_sqrt2_times_x()dans l'intervalle[-4.6, -4.5]par pas de0.01avec une valeur d'epsilonégale à10-5.
Appeler cette fonction dansmain(), le résultat attendu est :
derivative of sin_x_plus_cos_sqrt2_times_x( -4.6 ) = 0.199488derivative of sin_x_plus_cos_sqrt2_times_x( -4.59 ) = 0.170018derivative of sin_x_plus_cos_sqrt2_times_x( -4.58 ) = 0.140501derivative of sin_x_plus_cos_sqrt2_times_x( -4.57 ) = 0.110944derivative of sin_x_plus_cos_sqrt2_times_x( -4.56 ) = 0.08135derivative of sin_x_plus_cos_sqrt2_times_x( -4.55 ) = 0.0517246derivative of sin_x_plus_cos_sqrt2_times_x( -4.54 ) = 0.0220728derivative of sin_x_plus_cos_sqrt2_times_x( -4.53 ) = -0.0076006derivative of sin_x_plus_cos_sqrt2_times_x( -4.52 ) = -0.0372906derivative of sin_x_plus_cos_sqrt2_times_x( -4.51 ) = -0.0669923derivative of sin_x_plus_cos_sqrt2_times_x( -4.5 ) = -0.0967007
3.2. Recherche d'un zéro
- Définir une fonction de signature
double find_zero( std::function< double( double ) > func, double begin, double end, double precision );
qui retourne un nombre compris dans l'intervalle[begin, end]pour lequel le résultat de l'appel defuncsur ce nombre est inférieur en valeur absolue àprecision.
Cette fonction a pour précondition quefunc( begin )etfunc( end )sont de signes opposés ; si cette précondition n'est pas vérifiée, la fonction retournera NAN.
Vous procéderez par dichotomie.
Attention : le calcul sur les flottants ne donne pas toujours de résultat exact puisque tout réel ne peut pas être représenté. Ainsi, si begin et end sont des double, il est possible que :
( begin + end ) / 2 == begin ou ( begin + end ) / 2 == end
Il faudra dans ce cas arrêter la dichotomie même si la précision demandée n'est pas obtenue.
- Définir une fonction
test_32()qui cherche un zéro de la fonctionsin_x_plus_cos_sqrt2_times_x()dans l'intervalle[-2, 0]avec une précision de10-5.
Appeler cette fonction dansmain(), le résultat attendu est :
sin_x_plus_cos_sqrt2_times_x( -0.65065 ) = -9.37845e-06
La fonction std::abs(), déclarée dans <cmath>, retourne la valeur absolue de son argument.
4. Recherche des extrema
4.1. Recherche des zéros
- Définir une fonction de signature
int find_all_zeros( std::function< double( double ) > func, double begin, double end, double width, double precision, double results[], int max_number_of_results );qui cherche dans chaque intervalle de largeurwidth(de la forme[begin + n * width, begin + (n + 1) * width]oùnest un naturel quelconque), sans dépasserendcomme borne haute, un nombre pour lequel le résultat de l'appel defuncest inférieur en valeur absolue àprecision; au maximum,max_number_of_resultsseront retournés dans le tableauresults; la fonction a pour résultat le nombre exact de valeurs présentes dansresults. - Définir une fonction
test_41()qui cherche les zéros de la fonctionsin_x_plus_cos_sqrt2_times_x()dans l'intervalle[-10, 10], avec une largeur de0.5, une précision de10-5et un maximum de 10 zéros retournés.
Appeler cette fonction dansmain(), le résultat attendu est :
sin_x_plus_cos_sqrt2_times_x( -8.45839 ) = 3.33726e-06sin_x_plus_cos_sqrt2_times_x( -5.85583 ) = -6.30126e-05sin_x_plus_cos_sqrt2_times_x( -3.25323 ) = 3.65268e-06sin_x_plus_cos_sqrt2_times_x( -0.65065 ) = -9.37845e-06sin_x_plus_cos_sqrt2_times_x( 1.95193 ) = 5.49956e-07sin_x_plus_cos_sqrt2_times_x( 3.79224 ) = -4.83752e-07sin_x_plus_cos_sqrt2_times_x( 4.5545 ) = 4.40336e-06sin_x_plus_cos_sqrt2_times_x( 7.15709 ) = -1.13606e-05sin_x_plus_cos_sqrt2_times_x( 9.75967 ) = 6.98163e-06
4.2. Recherche des extrema
- Définir une fonction de signature
int find_all_extrema( std::function< double( double ) > func, double begin, double end, double width, double precision, double epsilon, double results[], int max_number_of_results );qui cherche dans chaque intervalle de largeurwidth(de la forme[begin + n * width, begin + (n + 1) * width]oùnest un naturel quelconque), sans dépasserendcomme borne haute, un extrema defunc, un extrema étant défini comme un nombre pour lequel la valeur estimée (calculée en utilisantepsilon) de la dérivée defuncen ce nombre est inférieur en valeur absolue àprecision; au maximum,max_number_of_resultsseront retournés dans le tableauresults; la fonction a pour résultat le nombre exact de valeurs présentes dansresults.
La difficulté est d'appeler la fonction find_all_zeros() avec pour argument func non pas la fonction reçue en argument, mais celle qui estime sa dérivée en un point.
Voici une solution possible pour résoudre cette difficulté :
- Définir une fonction lambda qui appelle
compute_derivative(): cette lambda doit capturer les argumentsfuncetespilonreçus comme arguments defind_all_zeros(), prendre un flottant en argument et appelercompute_derivative()avec ces trois éléments.
Une autre solution, si le compilateur que vous utilisez ne supporte pas les fonctions lambda est d'utiliser std::bind() de la bibliothèque standard : cette fonction vous permettrra d'obtenir une fonction basée sur compute_derivative() mais avec le premier et le troisième arguments fixés à func et espilon (reçus comme arguments de find_all_zeros()), alors que le deuxième argument sera std::placeholders::_1 (la fonction obtenue sera donc une fonction à un argument).
- Définir une fonction
test_42()qui cherche les extrema de la fonctionsin_x_plus_cos_sqrt2_times_x()dans l'intervalle[-10, 10], avec une largeur de0.5, une précision de10-5, une dérivée estimée en utilisant10-5pourepsilonet un maximum de 10 extrema retournés.
Appeler cette fonction dansmain(), le résultat attendu est :
sin_x_plus_cos_sqrt2_times_x( -9.44104 ) = 0.723454sin_x_plus_cos_sqrt2_times_x( -7.04443 ) = -1.54879sin_x_plus_cos_sqrt2_times_x( -4.53256 ) = 1.97584sin_x_plus_cos_sqrt2_times_x( -2.00695 ) = -1.86073sin_x_plus_cos_sqrt2_times_x( 0.479523 ) = 1.24009sin_x_plus_cos_sqrt2_times_x( 2.71632 ) = -0.352361sin_x_plus_cos_sqrt2_times_x( 4.18613 ) = 0.0701068sin_x_plus_cos_sqrt2_times_x( 6.11841 ) = -0.88052sin_x_plus_cos_sqrt2_times_x( 8.55212 ) = 1.65677