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 :

Probleme avec 0


Sujet :

Python

  1. #1
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 3
    Points : 1
    Points
    1
    Par défaut Probleme avec 0
    Bonjour a tous.
    Je viens chercher votre aide car j'ai un petit soucis et que je n'arrive pas a le résoudre.
    Je vous explique :

    Je travaille sur un projet d'analyse de fonction (relativement simple) et pour le moment, je désire dessiner le graphique d'une fonction donné. Pour lemoment, rien de très compliqué. En fait il n'y a rien de compliqué si ce n'est qu'il ne m'affiche pas les erreur qu'il devrait. Par exemple pour la fonction 1/x ou x vaudrait 0, python ne devrait pas le calculer. Cependant, il arrive a trouver une valeur. Je vous montre mon code ainsi que le résultat obtenu.
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    def dessinerGraphique():
     
        CanvasGraphique =  Canvas(Fenetre, width = 400.0, height=400.0)
     
        domaineDeDessin=[-10.0,10.0]
        intervalle=abs(domaineDeDessin[0])+abs(domaineDeDessin[1])
        echelle =  400.0/intervalle
        x=0.0
        y=0.0
        #Partie qui dessine le graphique vide.
        CanvasGraphique.create_line(200.0,0.0,200.0,400.0)
        CanvasGraphique.create_line(0.0,200.0,400.0,200.0)
     
        for i in xrange(0.0,intervalle):
            x=i*echelle
            CanvasGraphique.create_line(x,200+5,x,200-5)
            CanvasGraphique.create_line(200+5,x,200-5,x)
     
        fonction = EntreeFonction.get()
        #######################
     
        i=domaineDeDessin[0]
        premierPoint=True
        while(i<domaineDeDessin[1]):
            x=float(i)
            #Calcul de la coordonnée des points.
            try:
                #print i
                #print i+1.0
                print x
                y=eval(fonction)*echelle
                x=x*echelle
     
                print "f(",x/echelle,") = ",y/echelle
                #Ajuste les coordonnées des points pour etre dessinner.
                x=200+x
                y=200-y
     
                #Trace les points du graphique relier par une droite.
                if(premierPoint):
                    ancienPoint=[x,y]
                else:
                    CanvasGraphique.create_line(ancienPoint[0],ancienPoint[1],x,y)
                    ancienPoint=[x,y]
                premierPoint=False
            except:
                #print "zéro vaut bien zéro ni pus ni moins"
                CanvasGraphique.create_line((x*echelle)+200,0,(x*echelle)+200,400,fill='red')
    i+=float(intervalle)/200.0
    Résultat de l'analyse pour la fonction (f(x)=1/(x+1))

    pour x = -1.0
    i = -1.0
    i+1.0 = -1.86517468137e-14
    x = -1.0
    f( -1.0 ) = -5.36142812782e+13

    pour x = 0.0
    i = -1.87905246918e-14
    i+1 = 1.0
    x = -1.87905246918e-14
    f( -1.87905246918e-14 ) = 1.0

    J'espere que vous pourrez m'aidez, et que j'ai été assez clair.
    Merci d'avance.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 049
    Points : 1 380
    Points
    1 380
    Par défaut
    à vu de nez ... avec les float, faut s'attendre à des trucs bizares hein; genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1*1.1 = 1.1000000000000001
    forcement ça plus plus 1.1

  3. #3
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Non, le probleme ne se situe pas la. J'ai noté les resultat obtenu avec différentes valeurs en dessous du code. J'ai des nombre bizarre a la palce d'avoir un zéro des nombre du genre : 1.956231221-e152

  4. #4
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    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 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Cela vient de la façon dont les nombres sont représentés en mémoire. Comme ils sont stockés en binaire, certains nombres ne peuvent être représentés exactement, et de toutes façons, le nombre de chiffres significatifs est limité: environ 17 (Python utilise la bibliothèque du C), ce qui provoque des petites erreurs systématiques dans les calculs. C'est au programmeur de prendre en compte cette donnée dans l'organisation de son code. Certains algorithmes maladroits peuvent d'ailleurs donner des résultats complètement faux à cause de cela. Ce n'est pas un problème spécifique à Python: tous les langages qui calculent en flottant font ça.

    De ce fait, un calcul qui devrait théoriquement donner 0, donne à la place un résultat comme celui que tu cites. C'est donc à toi, en fonction du problème que tu as à résoudre, de définir en dessous de quelle petite valeur ton code doit restituer zéro exactement. Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    epsilon = 1.0e-15
    if x < epsilon: 
        x = 0.0
    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  5. #5
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    C'est simplement dû à un effet de cumul d'un minuscule écart entre la valeur théorique du pas et sa valeur approximée qui est représentée en interne.
    Cet écart est différent et se cumule de façon différente selon la valeur du pas. Pour certaines valeurs, il n'y a pas d'écart:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    for k in xrange(10,101,10):
        i = -k     # i part de -10,-20,-30,-40,etc
        pas = 0.1
        for u in xrange(k*10): # (k*10) ajouts de pas = + k
            i += pas
        print 'depart de i :',-k,'   i apres '+str(k)+'*10 ajouts de pas 0.1 :',i
     
    print
    for k in xrange(10,101,10):
        i = -k    # i part de -10,-20,-30,-40,etc
        pas = 0.5
        for u in xrange(k*2): # (k*2) ajouts de pas = + k
            i += pas
        print 'depart de i :',-k,'   i apres '+str(k)+'*2 ajouts de pas 0.5 :',i

    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
    depart de i : -10    i apres 10*10 ajouts de pas 0.1 : -1.87905246918e-14
    depart de i : -20    i apres 20*10 ajouts de pas 0.1 : 1.52933221642e-14
    depart de i : -30    i apres 30*10 ajouts de pas 0.1 : 1.57401869316e-13
    depart de i : -40    i apres 40*10 ajouts de pas 0.1 : 2.99510416468e-13
    depart de i : -50    i apres 50*10 ajouts de pas 0.1 : 4.4161896362e-13
    depart de i : -60    i apres 60*10 ajouts de pas 0.1 : 5.83727510772e-13
    depart de i : -70    i apres 70*10 ajouts de pas 0.1 : 2.99510416468e-13
    depart de i : -80    i apres 80*10 ajouts de pas 0.1 : -2.67480482208e-13
    depart de i : -90    i apres 90*10 ajouts de pas 0.1 : -8.35914670816e-13
    depart de i : -100    i apres 100*10 ajouts de pas 0.1 : -1.40434885942e-12
     
    depart de i : -10    i apres 10*2 ajouts de pas 0.5 : 0.0
    depart de i : -20    i apres 20*2 ajouts de pas 0.5 : 0.0
    depart de i : -30    i apres 30*2 ajouts de pas 0.5 : 0.0
    depart de i : -40    i apres 40*2 ajouts de pas 0.5 : 0.0
    depart de i : -50    i apres 50*2 ajouts de pas 0.5 : 0.0
    depart de i : -60    i apres 60*2 ajouts de pas 0.5 : 0.0
    depart de i : -70    i apres 70*2 ajouts de pas 0.5 : 0.0
    depart de i : -80    i apres 80*2 ajouts de pas 0.5 : 0.0
    depart de i : -90    i apres 90*2 ajouts de pas 0.5 : 0.0
    depart de i : -100    i apres 100*2 ajouts de pas 0.5 : 0.0

    Cet écart est lié au fait que le pas de ton itération est un nombre à virgule et que la valeur exacte de certains nombres à virgule ne peut pas être représentée par la représentation binaire "simple" sur laquelle repose la représentation des données dans les ordinateurs.

    J'ai rassemblé dans le post suivant quelques liens vers intéressants pour avoir plus d'informations:

    http://www.developpez.net/forums/d88...o/#post5034430



    Pour solutionner ton problème, tu as deux possibilités:

    - itérer sur des entiers et passer en float pour les calculs:

    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
    domaineDeDessin=[-10.0,10.0]
    intervalle=abs(domaineDeDessin[0])+abs(domaineDeDessin[1])
    pas_decimal = float(intervalle)/200.0
    print 'pas_decimal =',pas_decimal
    if pas_decimal<1:
        nd = len(str(pas_decimal).partition('.')[2])
        print 'nombre de decimales =',nd
        P = 10**nd
        print 'P =',P
        pas_entier = int(P*pas_decimal)
        print 'pas_entier =',pas_entier,type(pas_entier)
    E = int(P*domaineDeDessin[0])
    print 'valeur de depart :',E,type(E)
    while E < P*domaineDeDessin[1]:
        i = float(E) / P
        if -0.000001 < i < 0.000001:
            print 'faible valeur de i :',i
        E += pas_entier

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    pas_decimal = 0.1
    nombre de decimales = 1
    P = 10
    pas_entier = 1 <type 'int'>
    valeur de depart : -100 <type 'int'>
    faible valeur de i : 0.0

    - utiliser le module decimal:
    En complément de la représentation binaire "simple" dont je parlais plus haut, ce module assure une représentation sophistiquée des nombres à virgules qui apporte de nombreux avantages au niveu de leur affichage et des calculs qui en impliquent.
    Cela s'accompagne d'une vitesse d'exécution moindre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from decimal import *
     
    for k in xrange(10,101,10):
        i = -k     # i part de -10,-20,-30,-40,etc
        pas = Decimal('0.1')
        for u in xrange(k*10): # (k*10) ajouts de pas = + k
            i += pas
        print 'depart de i :',-k,'   i apres '+str(k)+'*10 ajouts de pas 0.1 :',i
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    depart de i : -10    i apres 10*10 ajouts de pas 0.1 : 0.0
    depart de i : -20    i apres 20*10 ajouts de pas 0.1 : 0.0
    depart de i : -30    i apres 30*10 ajouts de pas 0.1 : 0.0
    depart de i : -40    i apres 40*10 ajouts de pas 0.1 : 0.0
    depart de i : -50    i apres 50*10 ajouts de pas 0.1 : 0.0
    depart de i : -60    i apres 60*10 ajouts de pas 0.1 : 0.0
    depart de i : -70    i apres 70*10 ajouts de pas 0.1 : 0.0
    depart de i : -80    i apres 80*10 ajouts de pas 0.1 : 0.0
    depart de i : -90    i apres 90*10 ajouts de pas 0.1 : 0.0
    depart de i : -100    i apres 100*10 ajouts de pas 0.1 : 0.0

    EDIt
    grillé par tyrtamos: écart de 26 minutes sans rien voir !

  6. #6
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Merci, j'ai l'impression que c'est bien ca :p Tu m'aides beaucoup. Merci encore Je teste ca des que possible.

Discussions similaires

  1. Probleme avec la copie des surfaces
    Par Black_Daimond dans le forum DirectX
    Réponses: 3
    Dernier message: 09/01/2003, 10h33
  2. Problèmes avec le filtrage des ip
    Par berry dans le forum Réseau
    Réponses: 9
    Dernier message: 30/12/2002, 07h51
  3. probleme avec la touche F10
    Par b.grellee dans le forum Langage
    Réponses: 2
    Dernier message: 15/09/2002, 22h04
  4. Probleme avec fseek
    Par Bjorn dans le forum C
    Réponses: 5
    Dernier message: 04/08/2002, 07h17
  5. [Kylix] probleme avec un imagelist
    Par NicoLinux dans le forum EDI
    Réponses: 4
    Dernier message: 08/06/2002, 23h06

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