IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

comment faire un développement limité qui converge


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Rniamo
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    508
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 508
    Par défaut comment faire un développement limité qui converge
    Bonjour à tous,
    en cours j'ai abordé le C et en TD on a du faire la fonction cosinus via un dl (développemnt limité).
    J'ai voulu tester ma fonction sur un PC (c'est plus parlant quand même) et quelle ne fut pas ma surprise quand pour cos(33) j'ai obtenu plus de 3000!!!...il me semblait que |cos(x)|<=1!

    Donc voici ma question : comment corriger ceci (une bonne idée serait la bienvenue).

    Je joins mon code pour la fonction cos (basée sur le fait que cos(x)=somme ((-1^n)*(x^2n)/factoriel(2n)) :

    double cosinus(double x)
    {
    double resultat=0;double signe=1;double terme=1;long n=0;
    while (resultat+terme!=resultat)
    {
    resultat=resultat+signe*terme;
    signe=-signe;n=n+1;
    terme=terme*((x*x)/(2*n*(2*n-1)));
    }
    return resultat;
    }


    ma fonction est bonne certes mais [-24;24] est le plus grand intervalle où je peux avoir 6 décimales éxactes...un peu juste pour un supercalculateur...

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Tu fais une comparaison d'égalité sur des nombres à virgule flottante, c'est très mauvais.
    Tu dois tester si leur différence est inférieure à un certain seuil de tolérance...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Médinoc
    Tu fais une comparaison d'égalité sur des nombres à virgule flottante, c'est très mauvais.
    Tu dois tester si leur différence est inférieure à un certain seuil de tolérance...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #include <float.h>
     
       if (fabs(a - b) < DBL_EPSILON)
       {
          ...

  4. #4
    mat.M
    Invité(e)
    Par défaut
    Aaarghh attention en C/C++ les angles sont en radians
    Il faut les convertir donc en divisant par 180 et multiplier par PI ( ou vice versa )
    Ce qui ne semble pas le cas dans le code donné

    Tiens petite fonction de rotation ( Merci Mr Petzold )
    #define TWOPI ( 2* 3.14159)

    void RotatePoints(POINT pt[], int iNum, int iAngle)
    {
    int i ;
    POINT ptTemp ;

    for (i = 0 ; i < iNum ; i++)
    {
    ptTemp.x = (int) (pt[i].x * cos (TWOPI * iAngle / 360) +
    pt[i].y * sin (TWOPI * iAngle / 360)) ;

    ptTemp.y = (int) (pt[i].y * cos (TWOPI * iAngle / 360) -
    pt[i].x * sin (TWOPI * iAngle / 360)) ;

    pt[i] = ptTemp ;
    }
    }

  5. #5
    Membre éclairé Avatar de Rniamo
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    508
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 508
    Par défaut
    excusez moi mais

    -> vous vous trompez, je n'ai pas besoin de multiplier par 180 ; la fonction marche mais pour des petites valeurs (donc le 180 ne sert à rien...et surtout un dl est défini en radian...question d'homogéinité).

    -> la question n'était pas sur le test (ok il est nul mais je vais le corriger).

    Je repose donc ma question : pourquoi ma fonction dépasse le 1 majorant de la fonction
    x -> cos(x)
    ?

  6. #6
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #include <float.h>
     
       if (fabs(a - b) < DBL_EPSILON)
       {
          ...
    Même si on n'était pas dans un cas où l'égalité à du sens, ce test est beaucoup plus mauvais qu'un test d'égalité. Il revient à un test d'égalité pour des valeurs absolues plus grandes que 2, il est complètement absurde pour des valeurs inférieures à DBL_EPSILON.

  7. #7
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Même si on n'était pas dans un cas où l'égalité à du sens, ce test est beaucoup plus mauvais qu'un test d'égalité. Il revient à un test d'égalité pour des valeurs absolues plus grandes que 2, il est complètement absurde pour des valeurs inférieures à DBL_EPSILON.
    C'est ma fête en ce moment...

    J'ai pas compris pourquoi. Les paramètres et retour de fabs() ne sont pas de type double ? (j'aurais peut être dû vérifier, je me suis fié au 'f' comme 'double' !)

    Ca me parait correct :

    http://man.developpez.com/man3/fabs.3.php
    EDIT :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    #include <stdio.h>
    #include <math.h>
    #include <float.h>
     
    int is_equalf_ed (double a, double b)
    {
       return fabs (a - b) < DBL_EPSILON;
    }
     
    int main (void)
    {
       double n;
       int i = 0;
     
    #define MAX 0.001
    #define MIN -MAX
     
       for (n = MIN; n < MAX; n += 0.00001)
       {
          if (n == 0)
          {
             printf ("%f (%e) (n==0)\n", n, n);
          }
     
          if (is_equalf_ed (n, 0))
          {
             printf ("%f (%e) (is_nulf_ed)\n", n, n);
          }
     
          i++;
       }
       printf ("%d values tested from %e to %e\n", i, MIN, MAX);
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    0.000000 (1.927847e-018) (is_equalf_ed)
    200 values tested from -1.000000e-003 to 1.000000e-003
     
    Press ENTER to continue.

  8. #8
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    J'ai pas compris pourquoi
    Le problème sur les flottants, c'est que je suis à la limite de mes compétances. Il faudrait un Gaby ou un Laurent Deniau pour vérifier que je ne dise pas de grosses bétises.

    DBL_EPSILON, c'est le plus petit nombre tel que 1+DBL_EPSILON != 1, ce qui veut dire -- en supposant des flottants binaires -- que 2+DBL_EPSILON == 2.
    Donc pour a plus grand que deux fabs(a-b) < DBL_EPSILON, c'est la même chose que fabs(a-b) == 0.

    Si on part de l'autre coté, dans les nombres beaucoup plus petit que 1, faire fabs(a-b) < DBL_EPSILON, c'est prendre une marge relativement très grande. Donc il faut faire quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fabs(a-b) <= f * (fabs(a) + fabs(b))
    pour avoir une borne qui soit relative à la taille des nombres comparés.

    Quelle valeur prendre pour f? La ce n'est pas possible de se déterminer sans connaître le problème exact. Dans le cas présent d'une série convergente, f == 0 me ne semble pas être mauvais, s'il doit être non nul, le _EPSILON pour le type est un strict minimum et il me semble douteux que ce soit la bonne valeur: elle ne permet une différence que sur le bit le plus faible.

  9. #9
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Médinoc
    Tu fais une comparaison d'égalité sur des nombres à virgule flottante, c'est très mauvais.
    Tu dois tester si leur différence est inférieure à un certain seuil de tolérance...
    Les séries convergentes sont un des cas où un test d'égalité a du sens.

  10. #10
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Le problème est que les doubles ont une précision relative fixe. Pour que la série que tu emploies converge avec 6 chiffres significatifs, il faut que tous les calculs soient fait avec une précision absolue supérieure à ces 6 chiffres. Or, plus ton argument est grand, plus les résultats intermédiaires sont élevés. En calculant cos(24) tu as des résultats intermédiaires de l'ordre de 10^9, ce qui te permet d'avoir encore 6 chiffres significatifs sur le résultat; avec des nombres plus grands, tes résultats intermédiaires sont plus élevés également et tu commences à perdre en précision.

    Pour profiter au mieux de la précision des doubles, il faut d'abord réduire ton argument pour faire un calcul d'un sinus entre -PI/2 et PI/2.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 24/04/2008, 20h00
  2. Réponses: 8
    Dernier message: 26/03/2008, 16h58
  3. comment faire un document XML qui référence toutes les URL
    Par abdallah2007 dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 01/06/2007, 10h14
  4. [AJAX] Comment faire une boucle XMLHttpRequest qui marche ?
    Par lancelot_13 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 19/01/2007, 12h00
  5. [newbie]comment faire un mouseon/mouseover qui tri par ASC ou DESC?
    Par megapacman dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 30/06/2006, 13h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo