Conversion d'un flottant en chaîne sans l'arrondir


88

Je crée un programme qui, pour des raisons qui n'ont pas besoin d'être expliquées, nécessite qu'un float soit converti en une chaîne à compter avec len (). Cependant, str (float (x)) entraîne un arrondi de x lorsqu'il est converti en chaîne, ce qui annule le tout. Quelqu'un connaît-il un correctif pour cela? Voici le code utilisé si vous voulez savoir:

len(str(float(x)/3))

2
si x est à l'origine str, pourquoi la distribution?
Vinko Vrsalovic

1
-1: aucun exemple de la sortie requise pour différentes valeurs de x. Sans exemples, nous ne pouvons que deviner quel est le problème.
S.Lott

Réponses:


129

Une forme d'arrondi est souvent inévitable lorsqu'il s'agit de nombres à virgule flottante. En effet, les nombres que vous pouvez exprimer exactement en base 10 ne peuvent pas toujours être exprimés exactement en base 2 (que votre ordinateur utilise).

Par exemple:

>>> .1
0.10000000000000001

Dans ce cas, vous voyez .1 converti en chaîne en utilisant repr:

>>> repr(.1)
'0.10000000000000001'

Je pense que python coupe les derniers chiffres lorsque vous utilisez str () pour contourner ce problème, mais c'est une solution de contournement partielle qui ne remplace pas la compréhension de ce qui se passe.

>>> str(.1)
'0.1'

Je ne sais pas exactement quels problèmes "d'arrondi" vous cause. Peut-être feriez-vous mieux avec le formatage de chaîne comme moyen de contrôler plus précisément votre sortie?

par exemple

>>> '%.5f' % .1
'0.10000'
>>> '%.5f' % .12345678
'0.12346'

Documentation ici .


12
len(repr(float(x)/3))

Cependant, je dois dire que ce n'est pas aussi fiable que vous le pensez.

Les flottants sont entrés / affichés sous forme de nombres décimaux, mais votre ordinateur (en fait, votre bibliothèque C standard) les stocke sous forme binaire. Vous obtenez des effets secondaires de cette transition:

>>> print len(repr(0.1))
19
>>> print repr(0.1)
0.10000000000000001

L'explication sur pourquoi cela se produit est dans ce chapitre du tutoriel python.

Une solution serait d'utiliser un type qui suit spécifiquement les nombres décimaux, comme celui de python decimal.Decimal:

>>> print len(str(decimal.Decimal('0.1')))
3

Bon article sur la façon de travailler avec les résultats flottants de la division: stackoverflow.com/questions/2958684/python-division
Trutane

3

D'autres réponses ont déjà souligné que la représentation des nombres flottants est une question épineuse, pour dire le moins.

Puisque vous ne donnez pas assez de contexte dans votre question, je ne peux pas savoir si le module décimal peut être utile pour vos besoins:

http://docs.python.org/library/decimal.html

Entre autres, vous pouvez spécifier explicitement la précision que vous souhaitez obtenir (à partir de la documentation):

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

Un exemple simple de mon invite (python 2.6):

>>> import decimal
>>> a = decimal.Decimal('10.000000001')
>>> a
Decimal('10.000000001')
>>> print a
10.000000001
>>> b = decimal.Decimal('10.00000000000000000000000000900000002')
>>> print b
10.00000000000000000000000000900000002
>>> print str(b)
10.00000000000000000000000000900000002
>>> len(str(b/decimal.Decimal('3.0')))
29

Peut-être que cela peut aider? decimal est en python stdlib depuis 2.4, avec des ajouts en python 2.6.

J'espère que cela aide, Francesco


0

Je sais que c'est trop tard, mais pour ceux qui viennent ici pour la première fois, j'aimerais publier une solution. J'ai une valeur flottante indexet une chaîne imgfileet j'ai eu le même problème que vous. Voici comment j'ai résolu le problème

index = 1.0
imgfile = 'data/2.jpg'
out = '%.1f,%s' % (index,imgfile)
print out

La sortie est

1.0,data/2.jpg

Vous pouvez modifier cet exemple de mise en forme selon votre convenance.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.