Algorithme calcul Ln(x)

Résolu/Fermé
LittDev - Modifié par LittDev le 31/12/2015 à 13:29
 LittDev - 1 janv. 2016 à 00:42
Bonjour

J'ai créé un algorithme qui calcul le logarithme népérien de x, pouvez me dire en quoi puis-je l'améliorer ?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    double e=2.7182818285, x, X, y, p=1;
    int i;
    do
    {
    printf("x = ");
    scanf("%lf", &x);
    }
    while(x<=0);
    if(x<1)
    X=1/x;
    else
    X=x;
    for(i=0;i<11;i++)
    {
    while(X>e)
    {
        X/=e;
        y+=p;
    }
        p/=10;
        e=pow(e,0.1);
    }
    if(x<1)
    y*=-1;
    printf("Ln(%.6f) = %.9f\n", x, y);
    return 0;
}



Merci

2 réponses

fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
31 déc. 2015 à 13:49
Bonjour,

Mes remarques sur ton code:
Attention à l'indentation qui n'est pas régulière
Le bon prototype de main() sans argument est : int main(void)
Pourquoi ne pas utiliser la constante M_E inclus dans math.h plutôt que recréer une variable e ?
for(i=0;i<11...) => Ca serait peut-être mieux de rendre paramétrable 11 par un #define par exemple.

Qu'entends-tu par améliorer l'algorithme ?
Si c'est "rendre plus performant", le mieux est probablement d'implémenter un autre algorithme.
0
Bonjour

Oui justement je souhaiterais l'améliorer dans son écriture, pas dans ses performances (sans me vanter, il marche très bien)
J'ai aussi un peux de mal avec les virgules, le problème est que quand je tape un entier, ou un réel avec juste quelques virgules il m'affiche toujours toutes les virgules (genre 1.230000)
0
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
31 déc. 2015 à 13:53
Bonjour,

Je ne connais pas cet algorithme là mais puisque tu demandes de l'améliorer on va dire qu'il fonctionne déjà... Quelques remarques donc :

1) le choix des noms de variables est plutôt mauvais, quelqu'un qui lit ton programme ne peut pas savoir ce qu'elles font, x, y, p... ce n'est pas très explicite, alors quand en plus tu mélanges x et X, c'est galère !

2) e=2.7182818285, ceci est une approximation très... approximative.
Un double permet d'avoir 52 bits de précision, tu ne les utilises pas tous !
Pour un double tu devrais utiliser e=2.7182818284590452354

3) Pourquoi ta boucle for va de 0 à 11 ? Ça semble magique !
Idem, pourquoi faire la puissance de 0.1 ?

4) Ton résultat est un affichage, il pourrait être intéressant de faire une fonction qui prend un double en paramètre et renvoie un double en sortie.

5) Lors de l'affichage du résultat, il serait bien de montrer la différence entre le résultat obtenu avec ton calcul et le résultat obtenu avec la fonction de math.h
0
Salut

L'algorithme se base sur ça :
Tant que x>e on peut dire que :
Ln(x)=Ln(a*e^n) (Exemple : Ln(75)=Ln(1.37*e^4))
Tel que 1<a<e
Donc : Ln(x)=Ln(a)+4*Ln(e)=4+Ln(a)
Comme on a déjà le premier chiffre de Ln(75), c'est 4
On continue
Ln(a)=Ln(b*(e^0.1)^n1)=Ln(b)+n1*Ln(e^0.1)
Tel que
1<b<e^0.1
On sait que Ln(e^0.1)=0.1
Donc :
Ln(a)=Ln(b)+0.1*n1
Ln(x)=Ln(b)+n+0.1*n1
(Exemple : Ln(1.37)=Ln(1.02*(e^0.1)^0.3)=Ln(1.02)+0.3*Ln(e^0.1)=Ln(1.02)+0.3
Donc
Ln(75)=Ln(1.02)+4+0.3=Ln(1.02)+4.3)
On a la première décimale
Et on continue comme ça, à chaque fois en divisant sur 10 la puissance de e pour avoir plus de virgules

Le 11 c'est un paramètre de presicion, pour afficher 10 chiffres (9 après la virgule)
0
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
31 déc. 2015 à 17:21
Outre mes premières remarques, je poursuis suite à tes explications.

Si je comprends bien ton
for(i=0;i<11;i++) e=pow(e,0.1);
cela consiste à calculer les dix premiers chiffres en décimal...
Or en informatique les nombres ne sont pas calculés en décimaux mais en binaire... et pourquoi s'arrêter à 10 chiffres après la virgule ?
Il serait peut-être plus pertinent de calculer
for(i=0;i<52;i++) e=sqrt(e);
avec 52 le nombre de bits de précision d'un double et sqrt(e)==pow(e, 0.5)

Ensuite je ne vois pas trop le rapport entre :
Ton calcul mathématique :
Ln(x)=Ln(a*e^n) → Ln(x)=Ln(a)+n*Ln(e)

Et ton algorithme :
while(X>e) { X/=e; y+=p; }

Mais cela revient sûrement au problème de nommage de tes variables...

Remarque au passage : y n'est jamais initialisée.
0
Merci

Ça marche beaucoup mieux maintenant
A la base, j'ai voulu calculer les chiffres en décimaux pour contrôler le nombre de chiffres après la virgule qui pouvait être calculés
Mais c'est beaucoup mieux comme ça (il y a moins d'opérations finalement)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define precision 52

int main()
{
    double e=M_E, x, C, ln=0, r=1;
    int i;
    do
    {
    printf("x = ");
    scanf("%lf", &x);
    }
    while(x<=0);
    if(x<1)
    C=1/x;
    else
    C=x;
    for(i=0;i<precision;i++)
    {
    while(C>e)
    {
        C/=e;
        ln+=r;
    }
        r/=2;
        e=sqrt(e);
    }
    if(x<1)
    ln*=-1;
    printf("Ln(%.6lf) = %.17lf\n", x, ln);
    printf("Ln(%.6lf) = %.17lf\n", x, log(x));
    return 0;
}

Juste que il y a une petite différence entre la fonction de math.h et celle ci, dans les deux dernères décimales pouvant être calculées
0
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
31 déc. 2015 à 22:19
La valeur de M_E c'est 2.71828182845905 qui n'a que 48 bits de précision.
Essayes avec 2.7182818284590452354 comme je l'indiquais précédemment, cela devrait résoudre ton problème de précision sur les dernières décimales.
0
mmmm ça n'a rien changé
Mais c'est pas grave, c'est déjà très bien comme ça
En tous cas merci et bonne année à vous
Si il y a un autre truc qui cloche dites le moi svp
0