Parmi les fonctions mathématiques les plus importantes utilisées en informatique scientifique figure le logarithme népérien, généralement noté Ln(x). Cette fonction joue un rôle fondamental dans de nombreux domaines tels que les mathématiques, la physique, l'ingénierie, les statistiques, l'économie et le traitement numérique des données. Elle constitue l'inverse naturel de la fonction exponentielle et intervient dans une multitude de calculs liés aux croissances, aux décroissances, aux intérêts composés, aux probabilités et aux phénomènes naturels. Pourtant, malgré son importance considérable, il est souvent difficile de trouver des explications détaillées décrivant la manière dont un ordinateur peut calculer efficacement cette fonction à partir de ses fondements mathématiques. La plupart des ouvrages (Scientific Pascal,...) présentent le logarithme comme une fonction déjà disponible dans les bibliothèques logicielles, sans nécessairement expliquer les algorithmes employés pour obtenir une approximation numérique précise.
Après avoir consulté diverses références spécialisées, notamment des ouvrages consacrés à la programmation scientifique, des dictionnaires mathématiques et plusieurs manuels techniques, il apparaît que peu de sources détaillent réellement les mécanismes internes du calcul du logarithme. Bien que le langage C fournisse déjà des fonctions logarithmiques performantes au sein de sa bibliothèque mathématique standard, il demeure particulièrement instructif de comprendre comment ces résultats peuvent être obtenus à partir de calculs élémentaires. Parmi les références ayant servi d'inspiration, le projet GNU HaypoCALC propose plusieurs algorithmes numériques avancés permettant de reproduire diverses fonctions mathématiques avec une grande précision. Le programme présenté ci-dessous s'appuie sur des principes similaires afin de calculer le logarithme népérien sans utiliser directement les fonctions prédéfinies du langage.
L'algorithme procède en plusieurs étapes afin d'améliorer la stabilité et la précision des résultats. Il commence par normaliser la valeur à traiter, puis utilise une série de transformations mathématiques destinées à ramener l'argument dans une plage favorable aux calculs numériques. Une fonction de racine carrée spécialement développée est également employée afin de réduire progressivement la valeur jusqu'à obtenir une convergence rapide. Le calcul final repose ensuite sur un développement en série permettant d'approximer le logarithme avec une très grande exactitude. Les résultats obtenus sont comparables à ceux des bibliothèques mathématiques professionnelles et démontrent l'efficacité de cette approche.
Le programme en langage C affiche plusieurs valeurs du logarithme pour des nombres compris entre 0,1 et 1,9, ce qui permet de vérifier facilement la cohérence des résultats. On observe notamment que le logarithme est négatif pour les nombres compris entre 0 et 1, nul pour la valeur 1 et positif pour les nombres supérieurs à 1. Cet exemple constitue une excellente introduction aux méthodes numériques utilisées pour implémenter les fonctions mathématiques avancées. Il montre également comment des concepts tels que les développements en série, les transformations algébriques, les racines carrées et les propriétés du logarithme peuvent être combinés afin de reproduire une fonction essentielle des mathématiques modernes. Pour les programmeurs intéressés par le calcul scientifique, cet algorithme offre une occasion unique d'explorer les mécanismes internes habituellement dissimulés derrière les fonctions standard des bibliothèques mathématiques.
Bien qu'il existe de nombreuses fonctions de logarithme du langage C, il peut être intéressant d'effectuer les calculs par nous même :
Essayer maintenant !
- #include <stdio.h>
- #include <stdlib.h>
-
- double SquareRoot(double X) {
- double A,B,M,XN;
- if(X==0.0) {
- return 0.0;
- } else {
- M=1.0;
- XN=X;
- while(XN>=2.0) {
- XN=0.25*XN;
- M=2.0*M;
- }
- while(XN<0.5) {
- XN=4.0*XN;
- M=0.5*M;
- }
- A=XN;
- B=1.0-XN;
- do {
- A=A*(1.0+0.5*B);
- B=0.25*(3.0+B)*B*B;
- } while(B>=1.0E-15);
- return A*M;
- }
- }
-
- double Ln(double x) {
- int negatif = 0;
- double fois = 1;
- double ajout = 0;
- if(x<=0.0) return 0;
- if(x<1.0) {
- negatif = 1;
- x = 1.0/x;
- }
- while(x >= 10.0) {
- x /= 10.0;
- ajout += 2.302585092994046;
- };
-
- while(x>=1.1) {
- x = SquareRoot(x);
- fois *= 2;
- };
- x--;
- double savx = x;
- double i = 2;
- double xp = x*x;
- double quotient = (xp/i);
- double dl = x-quotient;
- while (1.0E-15<quotient) {
- i++;
- xp *= x;
- dl += (xp/i);
- i++;
- xp *= x;
- quotient = (xp/i);
- dl -= quotient;
- }
-
- dl *= fois;
- dl += ajout;
- if(negatif) dl = -dl;
- return dl;
- }
-
- int main()
- {
- double I;
- for(I=0;I<=2.0;I+=0.1) printf("Ln(%f)=%f\n",I,Ln(I));
- return 0;
- }
on obtiendra le résultat suivant :
Ln(0.0)=0.0000000000Ln(0.1)=-2.3025850930
Ln(0.2)=-1.6094379125
Ln(0.3)=-1.2039728043
Ln(0.4)=-0.9162907318
Ln(0.5)=-0.6931471806
Ln(0.6)=-0.5108256238
Ln(0.7)=-0.3566749440
Ln(0.8)=-0.2231435513
Ln(0.9)=-0.1053605157
Ln(1.0)=0.0000000000
Ln(1.1)=0.0953101798
Ln(1.2)=0.1823215568
Ln(1.3)=0.2623642645
Ln(1.4)=0.3364722366
Ln(1.5)=0.4054651081
Ln(1.6)=0.4700036292
Ln(1.7)=0.5306282511
Ln(1.8)=0.5877866649
Ln(1.9)=0.6418538862