Section courante

A propos

Section administrative du site

Après avoir consulté de nombreux ouvrages spécialisés, notamment Scientific Pascal, le Dictionnaire mathématique ainsi que plusieurs livres consacrés aux méthodes numériques, je n'ai trouvé que très peu d'explications détaillant l'algorithme complet permettant de calculer le logarithme népérien (Ln) avec une excellente précision. La plupart des auteurs se contentent de présenter la définition mathématique de cette fonction ou d'utiliser directement les bibliothèques fournies par le langage, sans expliquer la méthode de calcul employée. Parmi les rares exceptions figure le projet GNU HaypoCALC, dont les algorithmes constituent une excellente source d'inspiration pour comprendre les mécanismes internes de cette fonction fondamentale.

Le langage C++ offre déjà plusieurs fonctions logarithmiques dans l'entête math.h, telles que log, log10 ou encore log2, lesquelles sont généralement optimisées et adaptées aux différents processeurs modernes. Toutefois, il demeure particulièrement intéressant, tant sur le plan pédagogique que scientifique, de développer sa propre implémentation. Cette démarche permet de mieux comprendre les séries numériques, les méthodes d'approximation successives, les techniques de normalisation des valeurs ainsi que les différents compromis entre la rapidité d'exécution et la précision des résultats.

Le programme présenté ci-dessous illustre justement une telle approche. Après avoir réduit progressivement la valeur d'entrée dans un intervalle favorable au calcul, il exploite une fonction de racine carrée et un développement en série afin d'obtenir une approximation très précise du logarithme naturel. Cette méthode reproduit fidèlement les résultats attendus tout en démontrant qu'il est parfaitement possible d'implémenter soi-même une fonction logarithmique performante en C++, sans dépendre directement des fonctions prédéfinies de la bibliothèque standard. Les exemples qui suivent permettent de comparer les valeurs calculées pour différentes entrées et de constater la qualité ainsi que la précision de cette implémentation :

  1. #include <iostream>
  2.  
  3. double SquareRoot(double X) {
  4.   double A,B,M,XN;
  5.   if(X==0.0) {
  6.      return 0.0;
  7.   } else {
  8.      M=1.0;
  9.      XN=X;
  10.      while(XN>=2.0) {
  11.         XN=0.25*XN;
  12.         M=2.0*M;
  13.      }
  14.      while(XN<0.5) {
  15.         XN=4.0*XN;
  16.         M=0.5*M;
  17.      }
  18.      A=XN;
  19.      B=1.0-XN;
  20.      do {
  21.         A=A*(1.0+0.5*B);
  22.         B=0.25*(3.0+B)*B*B;
  23.      } while(B>=1.0E-15);
  24.      return A*M;
  25.   }
  26. }
  27.  
  28. double Ln(double x) {
  29.   int negatif = false;
  30.   double fois = 1;
  31.   double ajout = 0;
  32.   if(x<=0.0) return 0;
  33.   if(x<1.0) {
  34.     negatif = true;
  35.     x = 1.0/x;
  36.   }
  37.   while(x >= 10.0) {
  38.     x /= 10.0;
  39.     ajout += 2.302585092994046;
  40.   };
  41.  
  42.   while(x>=1.1) {
  43.     x = SquareRoot(x);
  44.     fois *= 2;
  45.   };
  46.   x--;
  47.   double savx = x;
  48.   double i = 2;
  49.   double xp = x*x;
  50.   double quotient = (xp/i);
  51.   double dl = x-quotient;
  52.   while (1.0E-15<quotient) {
  53.     i++;
  54.     xp *= x;
  55.     dl += (xp/i);
  56.     i++;
  57.     xp *= x;
  58.     quotient = (xp/i);
  59.     dl -= quotient;
  60.   }
  61.  
  62.   dl *= fois;
  63.   dl += ajout;
  64.   if(negatif) dl = -dl;
  65.   return dl;
  66. }
  67.  
  68. int main()
  69. {
  70.      for(double I=0;I<=2.0;I+=0.1) std::cout << "Ln(" << I << ")=" << Ln(I) << std::endl;
  71.      return 0;
  72. }

on obtiendra le résultat suivant :

Ln(0.0)=0.0
Ln(0.1)=-2.302585092994046
Ln(0.2)=-1.6094379124341056
Ln(0.3)=-1.2039728043259357
Ln(0.4)=-0.916290731874156
Ln(0.5)=-0.6931471805599471
Ln(0.6)=-0.5108256237659916
Ln(0.7)=-0.3566749439387316
Ln(0.8)=-0.22314355131420963
Ln(0.9)=-0.10536051565782642
Ln(1.0)=0.09531017980432469
Ln(1.2)=0.18232155679395437
Ln(1.3)=0.2623642644674894
Ln(1.4)=0.3364722366212136
Ln(1.5)=0.40546510810816594
Ln(1.6)=0.47000362924573785
Ln(1.7)=0.5306282510621684
Ln(1.8)=0.5877866649021186
Ln(1.9)=0.6418538861723971

Voir également

Science - Mathématique

Dernière mise à jour : Mardi, le 24 novembre 2015