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 :

test avec des valeurs flottantes


Sujet :

Python

  1. #1
    Membre averti Avatar de awalter1
    Inscrit en
    Août 2004
    Messages
    994
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 994
    Points : 407
    Points
    407
    Par défaut test avec des valeurs flottantes
    Bonjour,
    Je pense que mon post a déjà du être traité.
    Je viens de m'apercevoir d'un comportement anormal pour lequel je souhaiterais avoir une solution.
    Voilà le cas qui pose problème:
    [CODE]value = 0.0
    ...
    print "value=",value
    if value >= 100.0:
    print "Fin"

    Je me suis apercu que lorsque "value" vaut 100.0 (résultat du print), je ne passe pas dans le test "if value >= 100.0". Après recherche, si je fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    print value,value-100.0
    j'obtiens :
    100.0 -2.84... e-14
    En fait "value" vaut presque 100.0, Le print de "value" donne 100.0 ce qui me semble une erreur, mais bon, une fois qu'on le sait ...
    Cependant, y a t'il un moyen propre pour tester que "value" soit presque égal à 100.0.
    Merci

  2. #2
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 894
    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 : 3 894
    Points : 7 250
    Points
    7 250
    Par défaut
    Erreur? Non, ce n'est pas une erreur, mais une norme.


  3. #3
    Membre expérimenté
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    952
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2006
    Messages : 952
    Points : 1 351
    Points
    1 351
    Par défaut
    Salut,

    Citation Envoyé par awalter1 Voir le message
    y a t'il un moyen propre pour tester que "value" soit presque égal à 100.0.
    Merci
    définir une constante epsilon et vérifier si le nombre est > (100.0 - epsilon) ET < (100 +epsilon)? C'est un classique.

    A+

    Pfeuh

  4. #4
    Membre averti Avatar de awalter1
    Inscrit en
    Août 2004
    Messages
    994
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 994
    Points : 407
    Points
    407
    Par défaut
    oui c'est ce que je pensais.
    Merci

    PS : j'ai compris que si on veut la vrai valeur de "value" on fait alors que "print value" ne donne qu'une valeur arrondi.

  5. #5
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    PS : j'ai compris que si on veut la vrai valeur de "value" on fait
    La "vraie" ? même pas :

    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
    Python 2.6.6 (r266:84374, Aug 31 2010, 11:00:51) 
    [GCC 4.0.1 (Apple Inc. build 5493)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import math
    >>> math.pi
    3.1415926535897931
    >>> print math.pi
    3.14159265359
    >>> print str(math.pi)
    3.14159265359
    >>> print repr(math.pi)
    3.1415926535897931
    >>> print "%f" % math.pi
    3.141593
    >>> float("%f" % math.pi) == math.pi
    False
    C'est encore un peu plus sioux.

    Il faut distinguer la représentation interne et l'affichage qu'on peut en faire. Ca se résout avec une tolérance, à "epsilon près". Ou pas (cf géométries Shapely)

  6. #6
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut norme IEEE 754
    Par "désoeuvrement", je me suis attaqué un peu plus à cette fameuse IEEE 754 évoquée par fred1599 qui décrit comment sont codés les réels en machine. Ce document m'a permis de dégrossir les choses.

    Comme j'ai fait un peu de code, je le poste pour en faire profiter ceux que ça intéresse.

    Ca prend en entrée un réel (ou e ou pi), un éventuel deuxième argument qui doit valoir 4 ou 8 pour travailler en simple ou double précision (défaut : double précision)

    Le script affiche les bits des différentes parties (signe, exposant, mantisse) et reconstruit le nombre pour, enfin, comparer les 2 valeurs.

    Attention :

    • j'ai tout fait "à la main" car c'était le but - j'ai seulement utilisé le module struct
    • pas de traitement d'erreur / d'exception
    • je ne me suis préoccupé que du mode little endian
    • ça ne traite pas les valeurs particulières comme 0, NaN ou -NaN


    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    # -*- coding: utf-8 -*-
     
    from struct import pack, unpack
     
    # attention : on va traiter une chaine de caracteres (de bits)
    # en écriture "conventionnelle", avec les bits de poids forts à gauche
    # Les offsets sont données avec cette convention
    # avec les clés 'S'(igne), 'E'(xposant) et 'M'(mantisse)
    # ainsi que les chaines dans TITRE, DIZAINES, UNITES et ENTETE
     
    # pour bien montrer que l'on va du poids fort au poids faible
    TITRE    = { 4 : 'B31' + '.'*(32-5) + 'B0',
                 8 : 'B63' + '.'*(64-5) + 'B0'}
     
    # affichage des dizaines du nos de bits
    DIZAINES = { 4 : ''.join([str(i)+' '*9 for i in range(4)])[:32][::-1],
                 8 : ''.join([str(i)+' '*9 for i in range(7)])[:64][::-1]}
     
    # affichage des dizaines du nos de bits
    UNITES   = { 4 : ''.join(map(lambda n:str(n%10),range(32)))[::-1],
                 8 : ''.join(map(lambda n:str(n%10),range(64)))[::-1]}
     
    # on mixe les 3 lignes d'affichage
    ENTETE   = { 4 : '\n'.join((TITRE[4],DIZAINES[4],UNITES[4])),
                 8 : '\n'.join((TITRE[8],DIZAINES[8],UNITES[8]))}
     
    # où démarre chaque partie ?
    OFFSET = { 4: { 'S': 0, 'E':  1, 'M': 9},
               8: { 'S': 0, 'E':  1, 'M': 12}}
     
    # quelles tailles ont-elles ?
    SIZE   = { 4: { 'S': 1, 'E':  8, 'M': 23},
               8: { 'S': 1, 'E': 11, 'M': 52}}
     
    # décalage de l'exposant sur 4 et 8 octets
    DECALAGE = { 4 : -127, 8 : -1023}
     
    def dump_nombre(nombre,size):
     
        # liste des octets en mode little-endian - octets de poids fort à gauche
        octets = unpack('%dB' % size, pack('f' if size == 4 else 'd',nombre))
     
        # chaine avec les bits de b31 ou b63 (à gauche) à b0 (à droite)
        bits = ''.join([str((byte>>d)&1) for byte in reversed(octets) for d in range(7,-1,-1)])
     
        # visualisation des bits correspondants
        print ENTETE[size]
        print bits
     
        # et mise en évidence des différentes parties
        for p, partie in (('S','signe'),('E','exposant'),('M','mantisse')):
            start, end = OFFSET[size][p], OFFSET[size][p]+SIZE[size][p]
            chars = ['.']*(size*8)
            chars[start:end] = bits[start:end]  
            print ''.join(chars), partie
     
        # reconstruction du nombre : le signe
        start = OFFSET[size]['S']
        end   = start + SIZE[size]['S']
        str_signe = bits[start:end]
     
        signe = pow(-1,int(str_signe))
     
        print 'signe :', signe
     
        # reconstruction du nombre : l'exposant
        start = OFFSET[size]['E']
        end   = start + SIZE[size]['E']
        str_exposant = bits[start:end]
     
        exposant = 0
        for b, bit in enumerate(reversed(str_exposant)):
            exposant += int(bit) * pow(2,b)
     
        print 'exposant : %d%+d = %d' % (exposant,DECALAGE[size],(exposant+DECALAGE[size]))
        exposant += DECALAGE[size]
     
        # reconstruction du nombre : la mantisse
        start = OFFSET[size]['M']
        end   = start + SIZE[size]['M']
        str_mantisse = bits[start:end]
     
        mantisse = 0.
        print "contributions des bits de la mantisse"
        for b, bit in enumerate(str_mantisse,start=1):
            if bit == '0': continue
            current = 1./pow(2,b)
            print "\tB%-2d" %  (SIZE[size]['M']-b), current
            mantisse += current
     
        print "mantisse : (1 +) ", mantisse
     
        # le bit caché
        mantisse += 1.
     
        reconstruit = signe * pow(2,exposant) * mantisse
     
     
        print "au départ                    : %.16f" % nombre
        significatifs = 7 if size == 4 else 16
        fmt = "nombre reconstruit à la mano : %%.%df" % significatifs
        print fmt % reconstruit
     
        # test de l'égalité '==' entre les deux nombres
        # ATTENTION : si on a travaillé avec 4 octets, l'égalité n'est pas assurée
        # (certains rééels double précision NE peuvent PAS être EXACTEMENT retranscris en
        # réels simple précision)
        # pour vérifier que la reconstruction s'est quand même bien passée, on compare
        # le résultat via pack en réel simple précision
     
        print "egalite '==' entre les 2 valeurs           :", nombre == reconstruit
        if size == 4:
            print "égalité '==' entre pack('f') des 2 valeurs :", pack('f',nombre) == pack('f',reconstruit)
     
    if __name__ == '__main__':
     
        import sys
        import math
     
        if sys.argv[1].lower() == 'pi':
            nombre = math.pi
        elif sys.argv[1].lower() == 'e':
            nombre = math.e
        else:
            nombre = sys.argv[1]
     
        dump_nombre(float(nombre), int(sys.argv[2]) if 2 < len(sys.argv) else 8)

    Quelques exécutions :

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    plx@satellite:~/Bureau$ python ieee_754.py e 4
    B31...........................B0
     3         2         1         0
    10987654321098765432109876543210
    01000000001011011111100001010100
    0............................... signe
    .10000000....................... exposant
    .........01011011111100001010100 mantisse
    signe : 1
    exposant : 128-127 = 1
    contributions des bits de la mantisse
    	B21 0.25
    	B19 0.0625
    	B18 0.03125
    	B16 0.0078125
    	B15 0.00390625
    	B14 0.001953125
    	B13 0.0009765625
    	B12 0.00048828125
    	B11 0.000244140625
    	B6  7.62939453125e-06
    	B4  1.90734863281e-06
    	B2  4.76837158203e-07
    mantisse : (1 +)  0.359140872955
    au départ                    : 2.7182818284590451
    nombre reconstruit à la mano : 2.7182817
    egalite '==' entre les 2 valeurs           : False
    égalité '==' entre pack('f') des 2 valeurs : True
    plx@satellite:~/Bureau$ 
    plx@satellite:~/Bureau$ python ieee_754.py pi
    B63...........................................................B0
       6         5         4         3         2         1         0
    3210987654321098765432109876543210987654321098765432109876543210
    0100000000001001001000011111101101010100010001000010110100011000
    0............................................................... signe
    .10000000000.................................................... exposant
    ............1001001000011111101101010100010001000010110100011000 mantisse
    signe : 1
    exposant : 1024-1023 = 1
    contributions des bits de la mantisse
    	B51 0.5
    	B48 0.0625
    	B45 0.0078125
    	B40 0.000244140625
    	B39 0.0001220703125
    	B38 6.103515625e-05
    	B37 3.0517578125e-05
    	B36 1.52587890625e-05
    	B35 7.62939453125e-06
    	B33 1.90734863281e-06
    	B32 9.53674316406e-07
    	B30 2.38418579102e-07
    	B28 5.96046447754e-08
    	B26 1.49011611938e-08
    	B22 9.31322574615e-10
    	B18 5.82076609135e-11
    	B13 1.81898940355e-12
    	B11 4.54747350886e-13
    	B10 2.27373675443e-13
    	B8  5.68434188608e-14
    	B4  3.5527136788e-15
    	B3  1.7763568394e-15
    mantisse : (1 +)  0.570796326795
    au départ                    : 3.1415926535897931
    nombre reconstruit à la mano : 3.1415926535897931
    egalite '==' entre les 2 valeurs           : True
    plx@satellite:~/Bureau$ 
    plx@satellite:~/Bureau$ 
    plx@satellite:~/Bureau$ python ieee_754.py 3.12159 4
    B31...........................B0
     3         2         1         0
    10987654321098765432109876543210
    01000000010001111100100000100001
    0............................... signe
    .10000000....................... exposant
    .........10001111100100000100001 mantisse
    signe : 1
    exposant : 128-127 = 1
    contributions des bits de la mantisse
    	B22 0.5
    	B18 0.03125
    	B17 0.015625
    	B16 0.0078125
    	B15 0.00390625
    	B14 0.001953125
    	B11 0.000244140625
    	B5  3.81469726562e-06
    	B0  1.19209289551e-07
    mantisse : (1 +)  0.560794949532
    au départ                    : 3.1215899999999999
    nombre reconstruit à la mano : 3.1215899
    egalite '==' entre les 2 valeurs           : False
    égalité '==' entre pack('f') des 2 valeurs : True

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 322
    Points : 36 836
    Points
    36 836
    Par défaut
    Salut,
    Rien de bien nouveau concernant les float.
    A noter que Python apporte le module decimal qui peut traiter dans certains cas ces soucis de représentation.
    - W

  8. #8
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    bonsoir wiztricks

    Rien de bien nouveau concernant les float.
    Absolument : pas nouveau (comme - je suis gentil - 95 % des messages) et pas lié à Python. Mais les questions ayant trait à la "précision" et aux dernières décimales "bizarrement" non nulles reviennent régulièrement.

    J'ai trouvé que c'était l'occasion de "mettre les mains dans le cambouis", de montrer qu'on était dans le domaine du fini et du discret et de faire "sentir" que les maths théoriques, bien "proprettes", et l'informatique, ça pouvait faire deux.

    Tu trouves que j'ai eu tort, que c'était inutile ou hors-sujet et que j'aurais dû m'abstenir ?

  9. #9
    Membre éprouvé
    Avatar de afranck64
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 592
    Points : 1 006
    Points
    1 006
    Par défaut
    Citation Envoyé par plxpy Voir le message
    Tu trouves que j'ai eu tort, que c'était inutile ou hors-sujet et que j'aurais dû m'abstenir ?
    Non pour ma part. S'il est vrai que ca ne sert à rien de réinventer la roue, je pense qu'il est d'autant plus important de savoir des fois comment elle tourne.

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 322
    Points : 36 836
    Points
    36 836
    Par défaut
    Citation Envoyé par plxpy Voir le message
    Tu trouves que j'ai eu tort, que c'était inutile ou hors-sujet et que j'aurais dû m'abstenir ?
    Pas du tout.
    Au contraire, çà fait du bien de revoir les basiques de temps à autres.
    En plus çà permet de montrer tous les tracas que résoud un module tel que decimal et qui rendent Python bien plus simple que C.
    - W

  11. #11
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 894
    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 : 3 894
    Points : 7 250
    Points
    7 250
    Par défaut
    gmpy (que je ne connais pas) serait un module bien pratique dans le même sujet.

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

Discussions similaires

  1. [Selenium] Faire des tests avec des valeurs dynamiques (sans refaire le même scénario)
    Par geforce dans le forum Tests et Performance
    Réponses: 2
    Dernier message: 23/05/2010, 02h07
  2. [Débutant] Liste avec des valeurs associées aux string
    Par Bouillou dans le forum C++Builder
    Réponses: 3
    Dernier message: 16/03/2006, 18h11
  3. Trier une colonne avec des valeurs numériques ou textes
    Par jfc dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 07/02/2006, 11h15
  4. Problème de "select" avec des valeurs a null
    Par SchpatziBreizh dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 01/07/2005, 16h08
  5. Réponses: 6
    Dernier message: 04/04/2003, 15h28

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