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

Langage Perl Discussion :

[langage] Erreur d'arrondi sur petits nombres


Sujet :

Langage Perl

  1. #1
    Membre confirmé Avatar de Tchetch
    Inscrit en
    Mars 2002
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 401
    Points : 477
    Points
    477
    Par défaut [langage] Erreur d'arrondi sur petits nombres
    Bonjour,

    Je fais du PERL depuis peu et j'ai fais un petit programme qui effectuait des suites d'opérations très simples. En le faisant je me suis rendu compte d'une erreur d'arrondi et j'ai donc essayer le programme suivant (qui me semble très simple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/opt/perl/bin/perl
     
    $a = -1;
    $b = 0.1;
     
    while($a <= 1)
    {
            $a += $b;
            print $a . "\n";
    }
    Les résultats étant les suivants :
    -0.9
    -0.8
    -0.7
    -0.6
    -0.5
    -0.4
    -0.3
    -0.2
    -0.1
    -1.38777878078145e-16
    0.0999999999999999
    0.2
    0.3
    0.4
    0.5
    0.6
    0.7
    0.8
    0.9
    1
    1.1
    Il y a bien une erreur d'arrondi de la part de PERL. J'ai essayer ceci avec la version 5.8.3 et 5.8.6 (Linux SUSE 9.1), l'erreur est toujours la même. J'ai donc pris mon livre (PERL 5 de David Till (CampuPress)) et il m'indique qu'il existe une erreur d'arrondi sur les GRAND nombres à virgule flottante. Je ne pense pas qu'il s'agisse là de grand nombre.
    Je vous demande donc si vous connaissez un solution à ce problème ?

    Merci.

    T.
    Mon wiki (on y parle Debian principalement) : http://www.tchetch.net/

  2. #2
    Membre du Club
    Inscrit en
    Août 2004
    Messages
    50
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 50
    Points : 60
    Points
    60
    Par défaut
    Il y a bien sûr une erreur d'arrondi quand tu divises 1 par 10, car le résultat est stocké en forme binaire (0.000101010101010...) -- il est coupé quelque part.

    Pour opérer des fractions tu peux utiliser quelque modue pareil à Number::Fraction (http://search.cpan.org/~davecross/Nu...er/Fraction.pm), mais ça semble un peu trop dur.

    Pour formater tes nombres tu peux utiliser printf/sprintf (http://www.icewalkers.com/Perl/5.8.0...c/sprintf.html):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while ($a <= 1) { 
            $a += $b; 
            printf ("%.1f\n", $a);
    }
    Mais le meilleur est d'utiliser des intègres:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $a = -10; 
    $b = 0.1; 
     
    while (0.1 * $a <= 1) { 
            $a += 1; 
            print $a * 0.1 . "\n"; 
    }

  3. #3
    Membre confirmé Avatar de Tchetch
    Inscrit en
    Mars 2002
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 401
    Points : 477
    Points
    477
    Par défaut
    Citation Envoyé par dmitry_ovsianko
    Il y a bien sûr une erreur d'arrondi quand tu divises 1 par 10, car le résultat est stocké en forme binaire (0.000101010101010...) -- il est coupé quelque part.
    Mais je ne pensais pas que pour des valeurs de ce type on avait déjà ce genre de problèmes.
    Mais bon je suis assez content de Number::Fraction qui résoud mon problème.

    Merci beaucoup.

    T.
    Mon wiki (on y parle Debian principalement) : http://www.tchetch.net/

  4. #4
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Il ne s'agit pas "d'erreur d'arrondi", c'est juste inhérent à la façon dont sont stocké les float (et quelque soit leur taille, ce n'est pas le problème), et ce n'est pas spécifique à Perl, mais affecte tous les langages de programmation...

    --
    Jedaï

  5. #5
    Membre expert
    Avatar de 2Eurocents
    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    2 177
    Détails du profil
    Informations personnelles :
    Âge : 54
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 2 177
    Points : 3 166
    Points
    3 166
    Par défaut
    C'est d'ailleurs une des raison pour lesquelles tout bon prof d'Analyse Numérique, en IUT ou en école d'Ingé, doit apprendre à ses élèves qu'il ne faut jamais faire de tests d'égalité entre deux valeurs.

    Avec des flottants, on ne fait pas :
    mais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ... if ((a - b) < epsilon) ...
    ou (plus compliqué et plus risqué) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ... if ((b != 0) && (((a / b) -1) >= 0) && (((a / b) -1) < pourcentage_tolerance)) ...
    La FAQ Perl est par ici
    : La fonction "Rechercher", on aurait dû la nommer "Retrouver" - essayez et vous verrez pourquoi !

  6. #6
    Membre confirmé Avatar de Tchetch
    Inscrit en
    Mars 2002
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Mars 2002
    Messages : 401
    Points : 477
    Points
    477
    Par défaut
    Mais ce qui m'étonne quand même c'est que le même code en C ne fait pas ce genre d'erreur ... Je trouve vraiment bizzare une erreur pareil avec des chiffres aussi simple, j'ai essayer le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $a = -1;
    $b = 0.1;
    $c = 0;
    $d = $a;
    $n = 1;
     
    while($a <= 1)
    {
        $c = $n * $b;
        $a = $c + $d;
        print $a  . "\n";
        $n++;
    }
    Les résultats sont justes ! Je n'arrive pas à comprendre qu'une erreur pareil existe, je pensais qu'il y avait des algorithmes qui s'occupaient de gérer se genre d'erreur !
    Je parle de nombre simple, là il s'agit de nombre entre -1 et 1, avec 1 chiffre après la virgule. Je ne pense pas qu'un autre langage de programmation fasse une erreur de ce genre avec ces chiffres là. D'ailleur si c'était le cas, le programme suivant en C, devrait donner des valeurs fausses, pourtant elles sont justes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
     
    int main(int argc, char **argv)
    {
        float a = -1, b = 0.1;
     
        while(a < 1)
        {
            a += b;
            printf("%f\n", a);
        }
     
        return 0;
    }
    Enfin, il semblerait que ce soit normal !!!

    T.
    Mon wiki (on y parle Debian principalement) : http://www.tchetch.net/

  7. #7
    Membre du Club
    Inscrit en
    Août 2004
    Messages
    50
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 50
    Points : 60
    Points
    60
    Par défaut
    Pas tout à fait justes, mais c'est printf qui cache l'erreur inévitable.

    Le programme equivalent en Perl donne des chiffres aussi ronds:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $a = -1; 
    $b = 0.1; 
     
    while ($a <= 1) { 
            $a += $b; 
            printf ("%f\n", $a);
    }
    -0.900000
    -0.800000
    -0.700000
    -0.600000
    -0.500000
    -0.400000
    -0.300000
    -0.200000
    -0.100000
    -0.000000
    0.100000
    0.200000
    0.300000
    0.400000
    0.500000
    0.600000
    0.700000
    0.800000
    0.900000
    1.000000
    1.100000

  8. #8
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Oui, d'ailleurs on recommande toujours d'utiliser printf pour afficher des float en Perl, ça permet de cacher ces petits problèmes, mais ils sont présent en C aussi, tu n'a qu'à augmenter le nombre de chiffres après la virgule pour le vérifier. (et heureusement, il n'y a pas d'"algorithme" qui "corrige" ces erreurs, ça induirait un surcoût dangereux, vu qu'il faudrait pratiquement une IA ou des indications du programmeur pour savoir quand faire les corrections, les modules de calcul mathématique sont là pour ça : faire des calculs exacts à la demande)

    --
    Jedaï

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

Discussions similaires

  1. Erreurs d'affichage sur petits écrans
    Par tembe dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 10/05/2013, 15h42
  2. Problème d'arrondi sur les nombres décimaux
    Par marcandre dans le forum Développement
    Réponses: 2
    Dernier message: 17/01/2011, 16h29
  3. Erreurs de syntaxe sur mon petit prog :(
    Par LeonHONORE dans le forum Pascal
    Réponses: 5
    Dernier message: 22/04/2008, 11h30
  4. Réponses: 2
    Dernier message: 12/10/2005, 15h15
  5. Réponses: 3
    Dernier message: 08/09/2003, 15h06

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