Parmi les fonctions mathématiques fondamentales utilisées en informatique, la fonction exponentielle occupe une place particulièrement importante. Elle intervient dans une multitude de domaines, notamment les calculs financiers, les probabilités, la physique, la chimie, la croissance démographique, les modèles biologiques et les simulations scientifiques. Pourtant, malgré son importance, il est souvent difficile de trouver dans les ouvrages de programmation ou de mathématiques appliquées une description détaillée de son algorithme de calcul interne. Après consultation de nombreuses références, telles que Scientific Pascal, divers dictionnaires mathématiques et plusieurs ouvrages spécialisés, il apparaît que peu d'auteurs prennent le temps d'expliquer comment reproduire efficacement cette fonction à partir de ses fondements mathématiques.
La fonction exponentielle, généralement notée exp(x) ou e^x, est l'inverse naturel du logarithme népérien. Elle repose sur la célèbre constante mathématique e, dont la valeur approximative est 2,718281828459045. Les bibliothèques standard des langages modernes proposent presque toujours une fonction toute prête permettant de l'évaluer, mais il demeure extrêmement instructif de comprendre comment cette valeur peut être obtenue à l'aide d'un algorithme numérique autonome.
Le programme présenté dans cette page s'inspire d'une méthode utilisée dans le projet GNU HaypoCALC. L'idée consiste à décomposer progressivement la valeur à calculer afin de ramener le problème dans une plage numérique plus facile à traiter, puis à utiliser le développement en série de l'exponentielle pour obtenir une approximation très précise. Une succession d'opérations de mise à l'échelle et de recomposition permet ensuite de retrouver la valeur finale avec une excellente exactitude.
Le code source C++ ci-dessous démontre qu'il est possible de reproduire les résultats de la fonction standard exp() sans dépendre directement de l'implémentation de la bibliothèque mathématique du compilateur. Les exemples affichés comparent d'ailleurs les résultats obtenus par l'algorithme avec ceux de la fonction native du langage, mettant en évidence une précision remarquable. Cette approche constitue ainsi un excellent exercice pour comprendre les techniques de calcul numérique utilisées derrière les fonctions mathématiques que nous employons quotidiennement sans toujours connaître leur fonctionnement interne :
- #include <iostream>
- #include <math.h>
-
- double Exp(double x) {
- int inverse = false;
- double n = 0, dl = 1;
- int i = 1;
- if(x<0) {
- inverse = true;
- x = -x;
- }
- while(x >= 2) {
- x /= 2;
- n++;
- }
- x /= 16;
- n += 4;
- double q = x;
- while (q > 1.0E-15) {
- dl += q;
- i++;
- q = q*x/i;
- }
- for(i=1;i<= n; i++) dl=dl*dl;
- if(inverse) dl = 1/dl;
- return dl;
- }
-
-
- int main()
- {
- for(double I=0;I<=2.0;I+=0.1) {
- std::cout << "Exp(" << I << ")=" << Exp(I) << " " << exp(I) << " " << std::endl;
- }
- return 0;
- }
on obtiendra le résultat suivant :
Exp(0.0)=1.0 1.0Exp(0.1)=1.1051709180756477 1.1051709180756477
Exp(0.2)=1.221402758160166 1.2214027581601699
Exp(0.30000000000000004)=1.349858807576001 1.3498588075760032
Exp(0.4)=1.4918246976412661 1.4918246976412703
Exp(0.5)=1.6487212707001244 1.6487212707001282
Exp(0.6)=1.8221188003905087 1.8221188003905089
Exp(0.7)=2.0137527074704717 2.0137527074704766
Exp(0.7999999999999999)=2.225540928492434 2.2255409284924674
Exp(0.8999999999999999)=2.4596031111569396 2.4596031111569494
Exp(0.9999999999999999)=2.71828182845905 2.718281828459045
Exp(1.0999999999999999)=3.0041660239464347 3.004166023946433
Exp(1.2)=3.3201169227365463 3.3201169227365472
Exp(1.3)=3.669296667619233 3.6692966676192444
Exp(1.4000000000000001)=4.055199966844625 4.055199966844675
Exp(1.5000000000000002)=4.481689070338069 4.481689070338065
Exp(1.6000000000000003)=4.9530324243950865 4.953032424395117
Exp(1.7000000000000004)=5.473947391727178 5.473947391727202
Exp(1.8000000000000005)=6.04964746441294 6.049647464412949
Exp(1.9000000000000006)=6.685894442279275 6.685894442279273