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

Python Discussion :

deux nombres qui semblent égaux mais en fait non


Sujet :

Python

  1. #1
    Nouveau candidat au Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2
    Par défaut deux nombres qui semblent égaux mais en fait non
    Bonjour à tous.

    J'utilise Python pour écrire des scripts dans un logiciel de géomodélisation.
    Dans un de mes scripts, j'utilise une boucle while qui modifie un nombre b jusqu'à ce que celui-ci devienne entier.
    Pour ça, j'utilise le test while b != math.floor(b)
    Mais à ma grande surprise la boucle continue de tourner même une fois que b est devenu entier.
    Mon incomprehension est encore plus grande lorsque j'ajoute à la fin de ma boucle : print b
    print math.floor(b)
    print b-math.floor(b)
    En effet, il s'affiche alors des résultats étonnants comme
    2.0
    2.0
    2.6645352591e-015
    En gros, 2.0-2.0 = 2.6645352591e-015.
    J'ai d'abord pensé à un pb de type mais b et sa partie entière sont bien tous deux des float.

    Merci de m'expliquer ce qui se passe, et comment je puis faire pour que ma boucle s'arrête dès que b soit entier.

  2. #2
    Membre Expert Avatar de pacificator
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 074
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 074
    Par défaut
    Question de représentation: voir wikipython.flibuste.net

  3. #3
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 061
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 061
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> a=math.floor(2)
    >>> 2-a
    0.0
    No problemo

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> cmp(2,a)
    0 # les objets sont identiques
    No problemo

    No problemo

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> print 2.0-a
    0.0
    >>> print 2-a
    0.0
    >>> print cmp(2, a)
    0
    No problemo

    En conclusion le problème vient d'ailleurs, peux tu nous donner le code de ta boucle?

  4. #4
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    C'est un problème classique d'erreur numérique lorque l'on travaille avec des flottants. Avec d'autres langages (avec le C par ex.) tu aurais le même problème.

    Même si mathématiquement parlant ton algorithme converge exactement : sans rentrer dans les détails du fait qu'il existe des micros erreurs de calcul (dut au format de réprésentation des floats ou doubles en mémoire) ton b n'est pas exactement égal à 2.0 mais 2.000000000000000000001...
    Un simple print n'affiche que les premiers chiffres significatifs, mais le 0.000000000000000001 est bien là.

    Solution : se fixer une constante epsilon à peut prés égal à ce que tu considère comme l'erreur max acceptable, typiquement d'aprés ton exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    epsilon = 1e-14
    while math.fabs(b - math.floor(b)) > epsilon:
         ....

  5. #5
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    L'utilisation de "print" cache un peu le problème, parce qu'il "arrange" l'affichage.

    Si par contre, on utilise repr() ou le format "%r", on affiche quelque chose de plus proche de la représentation en mémoire:

    print 0.1, str(0.1), "%s" % 0.1
    0.1 0.1 0.1

    print repr(0.1), "%r" % 0.1
    0.10000000000000001 0.10000000000000001

    Tyrtamos

  6. #6
    Nouveau candidat au Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2
    Par défaut
    Oui c'est ça, vous avez raison, c'est excatement le problème décrit dans wikipython.flibuste.net.

    J'ai réglé le problème en utilisant le test while str(b) != str( math.floor(b) ) mais la technique de l'epsilon près doit fonctionner aussi.

    Merci d'avoir résolu mon souci.

    Ce qui est drôle, c'est que le même code écrit en TCL fonctionne sans creer de problèmes.

  7. #7
    Membre émérite Avatar de mchk0123
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    816
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 816
    Par défaut
    Je ne connais pas assez Tcl pour savoir pourquoi, mais peut-être que :

    - il utilise des rationnels : aucune erreur numérique
    ou, plus surement :
    - il utilise moins de chiffres significatifs pour la représentation de ses flottants : par exemple, un 'float' en python est en réalité équivalent à un double en C (alors que peut-être qu'un pour Tcl c'est un simple float C)

Discussions similaires

  1. [2008R2] fichiers TRN qui semblent "malformé" mais pourtant utilisable
    Par doubsman dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 10/07/2014, 11h32
  2. Problème de dépendance mais en fait non
    Par rodbeck dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 02/11/2009, 09h43
  3. Javascript ? Qui fonctionne mais en fait non
    Par le.squal dans le forum Général JavaScript
    Réponses: 18
    Dernier message: 01/02/2009, 10h04
  4. Réponses: 9
    Dernier message: 12/10/2006, 00h36

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