Forum Programmation.python Euh… comment dire… C'est bizarre.

Posté par (page perso) . Licence CC by-sa
Tags :
1
27
jan.
2016

Voici la trace de quelques calculs avec python que j'ai fait pour tester des trucs. J'en perds mon latin. Il y a bug la, non?

Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 275.15-20
255.14999999999998
>>> 275.15-17
258.15
>>> 275.15-18
257.15
>>> 275.15-19
256.15
>>> 275.15-20
255.14999999999998

Avec python3:

python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 10-275.15
-265.15
>>> 275.15-20
255.14999999999998
>>> 275.15-17
258.15
>>> 275.15-18
257.15
>>> 275.15-19
256.15
>>> 275.15-20
255.14999999999998```

C'est connu ? C'est la compilation de python sur Ubuntu ?
  • # deja...

    Posté par . Évalué à 2.

    ton python3 s'annonce en python2.7.6

    sur OSX j'ai le meme comportement

    en cherchant un peu, j'ai meme le comportement que ton 275.15-20
    à partir de 20…
    avec 275.25-21
    275.25-22
    275.25-23
    275.25-24

    275.25-31
    275.25-32
    275.25-33

    • [^] # Re: deja...

      Posté par . Évalué à 3.

      Mageia cauldron à jour X64 : pareil à partir de 20
      Pour le reste, je connais pas grand chose en python…

      Python 2.7.11 (default, Dec  8 2015, 13:50:42) 
      [GCC 5.3.0] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> 
      >>> 
      >>> 275.15-20
      255.14999999999998
      >>> 275.15-19
      256.15
      >>> 275.15-100
      175.14999999999998
      >>>
      
      
      Python 3.5.1 (default, Dec  9 2015, 13:07:55) 
      [GCC 5.3.0] on linux
      Type "help", "copyright", "credits" or "license" for more information.
      >>> 
      >>> 
      >>> 275.15-20
      255.14999999999998
      >>> 275.15-19
      256.15
      >>> 275.15-100
      175.14999999999998
      >>>
    • [^] # Re: deja...

      Posté par (page perso) . Évalué à 1.

      Oui petit problème de copier-coller…

  • # C'est le codage en virgule flottante

    Posté par . Évalué à 4.

    Rien à voir avec python, c'est le codage des floats (voir https://en.wikipedia.org/wiki/Single-precision_floating-point_format ).
    Important de pas utiliser des floats quand tu fais un programme où tu manipules des sommes d'argents…

  • # flottant = calcul à précision limitée

    Posté par . Évalué à 5.

    Rien que du très normal.

    Il te renvoies le résultat avec environ 16 chiffres significatifs. Pour des nombres réels stockés sur 64 bits (des doubles donc).

    https://fr.wikipedia.org/wiki/Virgule_flottante

    Concrètement, en programmation il faut se méfier de la comparaison entre deux nombre réels.

    On écrira pas, par exemple :

    if a == b:
       ...

    mais

    if abs (a - b) < epsilon:
       ...

    Avec un epsilon correctement dimensionné. De même il faut se méfier de la propagation de l’erreur dans des calculs complexes, mais là on rentre dans un sujet mathématique un peu plus ardu.

    Toi aussi ami, fasciste, réactionnaire, néo-nazi, antisémite, défenseur du patronat persécuté, viens rencontrer tes amis sur Linuxfr pour combattre cette engeance gauchiste islamophile qui viole ta femme, mange ton bébé et pratique la sodomie.

  • # Un peu de lecture

    Posté par . Évalué à 4.

    http://www.afpy.org/doc/python/2.7/tutorial/floatingpoint.html

    Pour résumer, un ordinateur travaille en binaire : la partie décimale d'un nombre flottant s'exprime comme la somme d'un nombre fini de fractions de puissances de 2 (1/2, 1/4, 1/8…). Il y a des valeurs que l'on ne peut pas représenter ainsi de façon exacte (par exemple, 0.1). L'ordinateur peut s'en approcher, suffisamment pour que tes calculs paraissent exacts, mais cette approximation peut te jouer des tours dans certaines conditions.

    Oh, et ce n'est pas lié à Python, c'est la même choses dans la plupart dans langages de programmation.

    • [^] # Re: Un peu de lecture

      Posté par . Évalué à -4. Dernière modification le 27/01/16 à 23:40.

      >>> Decimal(0.1) 
      Decimal('0.1000000000000000055511151231257827021181583404541015625')
      
      >>> Decimal(1) 
      Decimal('1')

      Donc si je comprend bien python stock les float avec une infime précision de division binaire qui force un arrondi ?

      Dans ce cas utiliser un multiplicateur sur les nombres que l'on manipule peut être une solution de contournement.

      • [^] # Re: Un peu de lecture

        Posté par . Évalué à 4.

        1 se code 1 en binaire
        et ne pose donc pas de probleme.

        0.1 en binaire se code … de maniere plus complexe et donne un nombre "proche de 0.1" mais qui n'est pas "0.1"

        sauf si evidemment tu demandes l'arrondi à 2 chiffres apres la virgule.
        ton 0.1000000000000000055511151231257827021181583404541015625
        s'affiche alors 0.10

        • [^] # Re: Un peu de lecture

          Posté par . Évalué à -7.

          On ne pourrait pas se passer des float et utiliser autre chose ?

          • [^] # Re: Un peu de lecture

            Posté par . Évalué à 4.

            hmmm, comment tu veux ecrire un nombre à virgule sans utiliser les flottants ?

          • [^] # Re: Un peu de lecture

            Posté par . Évalué à 4.

            Si, tu peux utiliser autre chose :

            • des doubles, pour être encore plus précis qu'un float ;
            • des structures à précision arbitraire (ex. https://gmplib.org/), pour avoir encore plus de précision ;
            • des structures rationelles (ex. http://www.boost.org/doc/libs/1_55_0/libs/rational/rational.html) , pour pouvoir représenter les nombres rationnels sans perte de précision ;
            • um moteur de calcul algébrique (ce que l'on trouve dans Maple, les calculettes scientifiques…), afin de travailler avec des nombres irrationnels (\sqrt{2}, \pi) ;

            Par contre, sache que :

            • Ces représentation vont prendre plus de place en mémoire ;
            • Les calculs liés à ces représentations vont être plus lourds ;
            • La précision offerte pas les floats et les doubles est suffisante dans 99.99% des cas.
            • [^] # Re: Un peu de lecture

              Posté par . Évalué à 6.

              La précision offerte pas les floats et les doubles est suffisante dans 99.99% des cas.

              Tu veux dire, dans 99.99000000000003214785613210 % des cas, j'imagine ?

              ­La faculté de citer est un substitut commode à l'intelligence -- Somerset Maugham

              • [^] # Re: Un peu de lecture

                Posté par . Évalué à 1.

                A vrai dire, j'avais envisagé de mettre 100%, mais je me suis retenu.

                • [^] # Re: Un peu de lecture

                  Posté par . Évalué à 2.

                  A vrai dire, j'avais envisagé de mettre 100%, mais je me suis retenu.

                  Ça n'est quand même pas vrai; il existe pas mal d'algos un peu compliqués dont le seul but est d'éviter une opération du style "multiplier par un très gros truc et diviser par un autre très gros truc" pour ne pas perdre trop de précision. Typiquement, calculer une variance "correctement" du point de vue informatique est beaucoup plus compliqué que d'appliquer la formule mathématique.

                  • [^] # Re: Un peu de lecture

                    Posté par . Évalué à 2.

                    Le 100%, c'était pour la blague du 99.99% arrondi…

                    Mais en effet, même 99.99%, c'est peut-être un peu gros. Ceci dis, cela fait 11 ans que je code, et je dois pouvoir compter sur les doigts d'une main le nombre de fois ou j'ai eu des problèmes de précision lié à un type flottant. Le dernier en date était justement un problème de variance, et avec une méthode destinée à justement éviter ce genre de gag, je m'en suis sorti avec de bons vieux floats.

            • [^] # Re: Un peu de lecture

              Posté par . Évalué à 2.

              La précision offerte pas les floats et les doubles est suffisante dans 99.99% des cas.

              En fait, quand on "dissèque" les besoins des utilisateurs, la plupart du temps, ils comprennent très bien la nécessité d'arrondir les nombres en virgule flottante. C'est juste l'arrondi "binaire" qui est très étrange, les gens s'attendent à avoir un arrondi décimal. Je me demande d'ailleurs si ça ne serait pas logique que les langages de haut niveau stockent et manipulent des "doubles décimaux", avec une partie int et une partie puissance de 10. Évidemment, on perdrait un peu en précision, mais on gagnerait largement en intuition…

              • [^] # Re: Un peu de lecture

                Posté par . Évalué à 1.

                cobol

                virgule fixe

                Toi aussi ami, fasciste, réactionnaire, néo-nazi, antisémite, défenseur du patronat persécuté, viens rencontrer tes amis sur Linuxfr pour combattre cette engeance gauchiste islamophile qui viole ta femme, mange ton bébé et pratique la sodomie.

              • [^] # Re: Un peu de lecture

                Posté par . Évalué à 1.

                Je me demande d'ailleurs si ça ne serait pas logique que les langages de haut niveau stockent et manipulent des "doubles décimaux", avec une partie int et une partie puissance de 10. Évidemment, on perdrait un peu en précision, mais on gagnerait largement en intuition…

                On perdrait surtout en temps de calcul.

                • [^] # Re: Un peu de lecture

                  Posté par . Évalué à 1.

                  On perdrait surtout en temps de calcul.

                  Significativement? On ferait deux opérations sur des entiers plutôt qu'une sur un flottant. Ce genre d'arithmétique pourrait être réservé à des types de données particuliers, évidemment qu'il ne serait pas question d'utiliser de tels pseudo-flottants pour des calculs de 3d.

                  On peut accuser les non-informaticiens de ne rien comprendre ou de ne pas faire d'efforts, mais il faut quand même admettre que la représentation des flottants est incohérente du point de vue "logique" (elle est cohérente du point de vue technique, mais pas logique). Par exemple:

                      float C =  1.26783;
                      float a = 1.26783;
                      if (a != C) printf("Pas possible");
                      if (a != 1.26783) printf("Comprends pas");
                  

                  Je ne sais pas où il faudrait faire le rapport de bug (compilateur, langage, hardware?), mais ce n'est pas parce qu'on est habitués à un bug et à la manière de le contourner que ça n'en est pas un.

                  • [^] # Re: Un peu de lecture

                    Posté par (page perso) . Évalué à 2.

                    Il n'y a pas de bug, tu compares des données de deux types différent, float vs double.
                    Change la ligne pour passer ton littéral exprimant un double en littéral exprimant un flottant… et le test d'égalité sera vrai.

                    if (a != (float)1.26783) printf("Comprends pas");

                    Si tu veux t'éloigner (un peu seulement) de la technique, laisse tomber le langage C, passe à Python3, où les nombres flottants sont tous en double du C, où 1/2 donnera 0.5. Mais tu auras toujours des problèmes de représentation à un moment donné, à part rester en calcul symbolique, dès que tu passe en numérique, ça coince. Par exemple, dès que tu commences à calculer avec des 1/3, en décimal ça coince.

                    Un outil pratique: http://www.h-schmidt.net/FloatConverter/IEEE754.html

                    Decimal Representation: 1.26783
                    Binary Representation: 00111111101000100100100001000001
                    Hexadecimal Representation: 0x3fa24841
                    After casting to double precision: 1.2678300142288208

                    Et sur la question de la perte en temps de calcul, oui ça serait significatif, dans certains domaines ce sont des milliards d'opérations, ça peut mouliner pendant des jours, tu ne peux pas te permettre d'être 10x ou 100x plus lent.

                    Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

                  • [^] # Re: Un peu de lecture

                    Posté par . Évalué à 1.

                    Ah mais l'ordinateur il s'en bat l'œil que tu ne comprenne pas son fonctionnement interne. Si cela fonctionne ainsi, c'est certainement parce que c'est la méthode la plus efficace. Après, libre à toi d'utiliser l'ensemble les briques de base fournies par ton langage de programmation préféré pour gérer ce genre de problème.

                    Moi je ne connais pas les subtilités d'un moteur à explosion, mais je ne transformerai pas voiture en voiture à pédale pour autant.

  • # Génial, merci pour l'info

    Posté par . Évalué à 2.

    C'est génial, je n'avais jamais remarqué que c'est des float en simple précision qui est implémenté par python. En même temps, je n'utilise pas énormément ce langage, presqu'uniquement pour de l'interface utilisateur. Un peu de lecture que je te recommande:
    https://docs.python.org/2/library/decimal.html
    https://en.wikipedia.org/wiki/IEEE_floating_point
    (sur mon environnement, sys.maxint=0x7FFFFFFF ce qui correspond bien à 32 bits pour coder signe, mantisse et exposant)
    Moi qui suis un fan des virgules fixes, voilà le bon moment pour jouer au troll! ^
    J'ai entre-aperçu que certains préconisent NumPy pour obtenir des précisions plus élevées qu'avec les packages de base de Python qui n'implémentent que IEEE754, mais je n'ai pas creusé le sujet, n'en ayant pas l'utilité pour l'instant. Si d'autres peuvent expliquer brièvement leur façon d'utiliser des doubles et quadruples précisions avec python, je serais intéressé.
    Le tout, c'est de le savoir.

    ps: en fait, j'aime aussi beaucoup les float mais surtout utiliser les bons outils pour le bon usage.

    • [^] # Re: Génial, merci pour l'info

      Posté par (page perso) . Évalué à 3.

      Non non, ce sont bien des double du C qui sont utilisés.

      Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

      • [^] # Re: Génial, merci pour l'info

        Posté par . Évalué à 1.

        Ah oui, les "float" du python sont des double" du C, au temps pour moi! C'est pour tromper l'ennemi ça!
        M'enfin, voilà comment est "stocké" la valeur 275.15 dans un format "double précision":

        Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32
        Type "help", "copyright", "credits" or "license" for more information.
        >>> from decimal import Decimal
        >>> Decimal(275.15)
        Decimal('275.1499999999999772626324556767940521240234375')
        >>>

        cqfd

    • [^] # Re: Génial, merci pour l'info

      Posté par (page perso) . Évalué à 1.

      C'est un peu pareil, je l'utilise surtout (python) comme calculatrice en ligne de commande car beaucoup plus pratique que bash pour faire des calculs.
      J'ai trouvé ce petit truc en testant en python les opérations de mon programme écrit en c++.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.