2014-09-17 1 views
17

En Python 2.7, repr d'un float renvoie le nombre décimal le plus proche jusqu'à 17 chiffres; ceci est suffisamment précis pour identifier de manière unique chaque valeur possible de point flottant IEEE. str d'un float travaillé de manière similaire, sauf qu'il a limité le résultat à 12 chiffres; Dans la plupart des cas, il s'agit d'un résultat plus raisonnable et il vous isole des légères différences entre la représentation binaire et décimale.Pourquoi str (float) retourne plus de chiffres dans Python 3 que dans Python 2?

Python 2 demo: http://ideone.com/OKJtxv

print str(1.4*1.5) 
2.1 
print repr(1.4*1.5) 
2.0999999999999996 

En Python 3.2, il apparaît str et repr renvoient la même chose.

Python 3 demo: http://ideone.com/oAKRsb

print(str(1.4*1.5)) 
2.0999999999999996 
print(repr(1.4*1.5)) 
2.0999999999999996 

Y at-il un PEP qui décrit le changement, ou une autre déclaration de quelqu'un responsable?

+2

On dirait que le problème [# 1580] (http://bugs.python.org/issue1580) pourrait être pertinent ici. Il y a aussi une note sur ce changement dans [Nouveautés de Python 3.1: Autres changements de langue] (https://docs.python.org/3/whatsnew/3.1.html#other-language-changes) (dernière puce). –

+6

Je suppose que c'est celui-ci: http://bugs.python.org/issue9337 – georg

+0

Python 3.1 a ajouté une nouvelle fonctionnalité pour cacher les erreurs d'arrondi non pertinentes en arrondissant à la fraction décimale _shortest_ dans un epsilon du flottant, au lieu de _closest_, Le hack à 12 chiffres n'est donc plus nécessaire. – abarnert

Répondre

25

Non, il n'y a pas de PEP. Il y a un issue dans le traqueur de bogues, et un associated discussion dans la liste de diffusion des développeurs Python. Bien que j'étais responsable de proposer et de mettre en œuvre le changement, je ne peux pas prétendre que c'était mon idée: il est apparu lors de conversations avec Guido à EuroPython 2010.

Quelques détails supplémentaires: comme déjà mentionné dans les commentaires, Python 3.1 a introduit un nouvel algorithme pour la chaîne repr d'un float, (plus tard rétroporté à la série Python 2, de sorte qu'il apparait également dans Python 2.7). À la suite de ce nouvel algorithme, un nombre décimal "court" saisi à l'invite a une représentation courte correspondante. Ceci a éliminé l'une des raisons existantes pour la différence entre str et repr, et a permis d'utiliser le même algorithme pour str et repr. Donc pour Python 3.2, suite à la discussion liée à ci-dessus, str et repr ont été rendus identiques. Quant à savoir pourquoi: cela rend le langage un peu plus petit et plus propre, et il supprime le choix plutôt arbitraire de 12 chiffres lors de la sortie de la chaîne. (Le choix de 17 chiffres utilisés pour les repr dans les versions Python antérieures à 2.7 est loin d'être arbitraire, en passant: deux flottants IEEE 754 binary64 distincts auront des représentations distinctes lorsqu'ils seront convertis en décimal avec 17 chiffres significatifs, et 17 est le plus petit entier avec cette propriété.)

En dehors de la simplicité, il y a des avantages moins évidents. Un aspect de la distinction repr par rapport à str qui a été source de confusion pour les utilisateurs dans le passé est le fait que repr est automatiquement utilisé dans les conteneurs. Ainsi, par exemple en Python 2.7:

>>> x = 1.4 * 1.5 
>>> print x 
2.1 
>>> print [x] 
[2.0999999999999996] 

Je suis sûr qu'il ya au moins une question StackOverflow poser des questions sur ce phénomène quelque part: here is one such et another plus récente. Avec la simplification introduite dans Python 3.2, nous obtenons ceci à la place:

>>> x = 1.4 * 1.5 
>>> print(x) 
2.0999999999999996 
>>> print([x]) 
[2.0999999999999996] 

qui est au moins plus cohérent.

Si vous voulez pouvoir masquer les imprécisions, la bonne façon de procéder reste la même: utilisez le formatage des chaînes pour un contrôle précis du format de sortie.

>>> print("{:.12g}".format(x)) 
2.1 

J'espère que cela explique une partie du raisonnement derrière le changement. Je ne vais pas prétendre que c'est universellement bénéfique: comme vous l'avez souligné, l'ancien str avait l'effet secondaire commode de cacher les imprécisions. Mais à mon avis (bien sûr, je suis partial), cela aide à éliminer quelques surprises de la langue.

+0

Merci pour l'info, c'est exactement ce que je cherchais. Je souhaite juste qu'il y ait un équivalent à la spécification de format 'g' qui n'a pas basculé arbitrairement en notation scientifique, je l'évite pour cette raison. –

+0

D'accord; J'ai souvent souhaité que la mise en forme des chaînes soit un peu plus configurable. Un jour peut-être. –

+0

P.S. Je ne suis pas sûr que j'achète l'argument que la sortie d'un objet doit être la même que la sortie d'une liste contenant l'objet, c'est * encore * pas le cas pour les chaînes contenant des caractères non imprimables: http://ideone.com/zNauZB –

Questions connexes