Gabriel Ozouf

Gabriel Ozouf — 13 septembre 2021

Fenêtre sur courbe

Avant la mise à jour 15.3.0, les courbes de notre application fonctions étaient certes très joliement dessinées, mais le zoom appliqué laissait parfois à désirer. Pour pallier à ce problème, nous avons dû développer un algorithme capable de calculer un repère adapté à chaque fonction.

Des problèmes d’échelle

Un grapheur est un outil pédagogique puissant pour un élève découvrant les mathématiques. Il l’aide à se familiariser avec les notions de l’analyse, à explorer les différents types de fonctions pour en découvrir les propriétés. Prenons l’exemple d’un élève qui souhaite se faire une idée des variations de la fonction f(x)=x(x-1)(x-3). Il entre l’expression dans l’application Fonctions de sa calculatrice, avec la version 14 de notre logiciel…

Courbe y=x(x-1)(x-3), réglages par défaut, Epsilon 14.4.0

… et se rend ainsi compte que cette fonction est strictement croissante, avec une unique racine en zéro ?

Heureusement pour nous, cet élève n’a pas somnolé pendant ses cours de mathématiques, et sait très bien que cette fonction n’est pas monotone. Sa calculatrice lui mentirait-elle ? Le grapheur dit bien la vérité, mais le zoom choisi ne fait pas honneur à ce polynôme du troisième degré… Ne serait-ce pas mieux si la fenêtre proposée ressemblait davantage à ceci ?

Courbe y=x(x-1)(x-3), réglée pour bien voir les graduations, Epsilon 15.3.0

Un algorithme un peu trop simple

Comment la calculatrice a-t-elle décidé de cette fenêtre, décidément sous-optimale, pour afficher la courbe ?

Jusqu’à la version 14, l’algorithme employé était très simple. Par défaut, l’axe horizontal s’étendait de -10 à 10, et l’axe vertical était choisi pour afficher l’intégralité de la courbe.

Sur la première image, les limites de l’axe des ordonnées sont donc les valeurs extrêmes de la courbe, ici f(-10)=-1430 et f(10)=630. Sachant que les extrema locaux de la fonction ont des valeurs de l’ordre de l’unité, pas étonnant qu’ils soient complètement invisibles.

Pour la version 15, nous avons décidé de mettre à jour notre grapheur pour qu’il soit capable de zoomer sur les courbes de façon bien plus intelligente.

C’est un problème complexe, car l’idée sous-jacente est assez subjective : qu’est-ce qui rend une portion de courbe plus intéressante qu’une autre ? Et surtout, comment traduire cette notion en langage mathématique ?

La première étape a donc été de compiler une liste de fonctions courantes, avec pour chacune le zoom auquel s’attendrait l’utilisateur. Cette liste a permis de valider notre solution, en s’assurant que les zooms qu’elle propose ne s’écartent pas trop de ceux recherchés.

Comme illustré dans l’exemple d’introduction, la meilleure fenêtre se concentre souvent sur les variations de la courbe. Avec ce constat comme point de départ, on peut énumérer les différents types de points d’intérêts que l’on souhaite afficher à l’écran : racines, minima et maxima, asymptotes verticales et horizontales.

À la recherche de points intéressants

La première étape de la construction d’un repère pour l’affichage d’une courbe cartésienne va donc être de trouver les points d’intérêts de la fonction.

Pour certaines catégories de courbes, la recherche de racines ou d’extrema est un problème déjà résolu, notamment dans le cas des polynômes de degré faible. Mais en général, il n’existe pas de méthode de résolution formelle ; on se contentera donc d’une résolution approchée.

On pourrait croire que cette question est elle aussi bien documentée, et la littérature est en effet abondante sur le sujet de la recherche de racines ou extrema dans un intervalle fini donné. Mais les documents se font plus rares lorsque cet intervalle est l’ensemble des réels.

Il est classique pour un algorithme de recherche de racines ou d’extrema de parcourir l’intervalle en calculant des valeurs de la fonction, à des abscisses régulièrement espacées… En comparant des valeurs consécutives, on peut savoir si la fonction change de signe ou de sens de variation.

Pour adapter ce schéma à l’ensemble des réels, nous utilisons une progression géométrique plutôt qu’arithmétique. Cette idée se fonde sur le constat suivant : pour la plupart des fonctions que nous avons rencontrées, la distance entre deux points d’intérêts est souvent du même ordre de grandeur que l’abscisse des points d’intérêts eux-mêmes. On peut donc étudier finement la fonction autour de zéro et explorer ses variations pour de grandes abscisses en un temps raisonnable.

Sur la fonction f introduite précédemment, on trouve cinq points d’intérêts (trois racines et deux extrema locaux), tous contenus dans l’intervalle [0, 3]. On ajoute une marge pour mieux centrer la courbe, ce qui donne un intervalle horizontal autour de [-2, 5]

Deuxième dimension

La deuxième étape est de déterminer l’intervalle affiché sur l’axe des ordonnées.

Nous cherchons d’abord s’il est possible de créer un repère orthonormé, plus naturel. Puisque nous connaissons déjà l’intervalle horizontal et le ratio de l’écran, nous pouvons en déduire la taille de l’intervalle vertical. Pour la fonction f, si l’écran a un ratio de 60%, nous devons trouver un intervalle vertical de taille (5 - (-2)) x 60% soit 4.2

Reste à déterminer sa position. Pour cela, nous calculons un échantillon des valeurs de la fonction, et cherchons l’intervalle de taille fixée qui contient le nombre maximal de ces valeurs, tout en vérifiant que les points d’intérêts trouvés précédemment appartiennent bien à cet intervalle. Nous construisons ainsi le repère orthonormé maximisant la place occupée par la courbe sur l’écran.

Un repère orthonormé trop bas par rapport à la courbe

Un repère orthonormé qui maximise la portion de courbe affichée

Un repère orthonormé trop haut par rapport à la courbe

Il n’est parfois pas possible de construire de repère orthonormé satisfaisant, par exemple parce que la taille de l’intervalle vertical n’est pas suffisante pour afficher tous les points d’intérêts.
Considérons par exemple la fonction 2f, qui a donc les mêmes variations que f. Elle atteint à son maximum local environ 1.3, et à son minimum local environ -4.2. Impossible donc d’afficher ces deux valeurs simultanément avec un intervalle vertical de taille 4.2

Le minimum et le maximum de la courbe ne peuvent pas être présent en même temps à l'écran avec ce repère orthonormé

Dans ce cas, nous calculons une mesure de l’ordre de grandeur de la fonction, la moyenne du logarithme de sa valeur absolue. Cette grandeur indique si la fonction prend plutôt ses valeurs dans les dizaines, les centaines, les milliers… Nous n’affichons pas les valeurs trop grandes par rapport à l’ordre de grandeur moyen. Ceci permet par exemple de couper les branches divergentes des courbes polynomiales ; si elles étaient incluses dans la fenêtre, leur croissance très rapide aurait pour effet d’écraser le reste de la courbe. C’est ce qui se produit dans l’exemple d’introduction.

Une affaire de compromis

L’algorithme de zoom automatique présent sur la version 15 d’Epsilon est considérablement plus complexe que l’algorithme basique que nous utilisions auparavant ; il est donc également bien plus instable.

Un algorithme simple aura un comportement prévisible, aussi bien dans ses réussites que dans ses échecs. Lorsque la procédure pour afficher une courbe se résume à dessiner toutes ses valeurs entre -10 et 10, elle échoue toujours de la même façon.

À l’inverse, avec la nouvelle méthode, on démultiplie le nombre de bugs, de cas particuliers et de paramètres à choisir. Le parcours de l’axe horizontal peut louper un extremum si son pas est trop grand, mais peut aussi être beaucoup trop lent si ce même pas est trop petit. La recherche de repère orthonormé peut être mise en défaut si la fonction est trop régulière : elle ne peut pas choisir le meilleur intervalle puisqu’ils se valent tous. Le calcul de la moyenne logarithmique peut être rendu caduque si les valeurs de la fonction sont trop souvent nulles. Certaines courbes n’ont tout simplement pas de points d’intérêts et doivent être ramenées à un intervalle par défaut…

Le travail ne s’arrête pas là, puisque les nouvelles capacités du grapheur nous ont amenés à repenser complètement l’interface de notre application Fonction !

L’application finale est un outil bien plus pratique pour les utilisateurs, même si le prix est un code un peu plus capricieux pour nous les développeurs.

Gabriel Ozouf
Gabriel Ozouf — Développeur

Gabriel a rejoint NumWorks en 2020 en tant que développeur après avoir reçu son diplôme d'ingénieur des Mines. Si votre calculatrice s'améliore chaque jour avec des nouvelles fonctionnalités, c'est en grande partie grâce à lui. Malgré tous ses succès, Gabriel a su garder la tête froide grâce au thermostat de son bureau réglé sur 18°C !