Conversione di un float in una stringa senza arrotondarlo


88

Sto realizzando un programma che, per motivi non necessari da spiegare, richiede che un float venga convertito in una stringa da contare con len (). Tuttavia, str (float (x)) fa sì che x venga arrotondato quando convertito in una stringa, il che getta via l'intera cosa. Qualcuno sa di una soluzione per questo? Ecco il codice utilizzato se vuoi sapere:

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

2
se x è originariamente str, perché il cast?
Vinko Vrsalovic

1
-1: nessun esempio dell'output richiesto per diversi valori di x. Senza esempi, possiamo solo indovinare qual è il problema.
S.Lott

Risposte:


128

Qualche forma di arrotondamento è spesso inevitabile quando si tratta di numeri in virgola mobile. Questo perché i numeri che puoi esprimere esattamente in base 10 non possono sempre essere espressi esattamente in base 2 (che usa il tuo computer).

Per esempio:

>>> .1
0.10000000000000001

In questo caso, stai vedendo .1 convertito in una stringa usando repr:

>>> repr(.1)
'0.10000000000000001'

Credo che Python tagli le ultime cifre quando usi str () per aggirare questo problema, ma è una soluzione alternativa parziale che non sostituisce la comprensione di cosa sta succedendo.

>>> str(.1)
'0.1'

Non sono sicuro di quali problemi ti stia causando l '"arrotondamento". Forse faresti meglio con la formattazione delle stringhe come un modo per controllare più precisamente il tuo output?

per esempio

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

Documentazione qui .


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

Tuttavia devo dire che questo non è affidabile come pensi.

I float vengono immessi / visualizzati come numeri decimali, ma il computer (in effetti, la libreria C standard) li memorizza come binari. Ottieni alcuni effetti collaterali da questa transizione:

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

La spiegazione del motivo per cui questo accade è in questo capitolo del tutorial di Python.

Una soluzione sarebbe quella di utilizzare un tipo che tiene traccia in modo specifico dei numeri decimali, come quello di Python decimal.Decimal:

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

Buon posto per quanto riguarda il modo di lavorare con i risultati galleggiante di divisione: stackoverflow.com/questions/2958684/python-division
Trutane

3

Altre risposte hanno già sottolineato che la rappresentazione dei numeri fluttuanti è una questione spinosa, per non dire altro.

Dato che non fornisci abbastanza contesto alla tua domanda, non posso sapere se il modulo decimale può essere utile per le tue esigenze:

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

Tra le altre cose puoi specificare esplicitamente la precisione che desideri ottenere (dalla documentazione):

>>> 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 semplice esempio dal mio prompt (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

Forse questo può aiutare? decimal è in python stdlib dalla 2.4, con aggiunte in python 2.6.

Spero che questo aiuti, Francesco


0

So che è troppo tardi ma per coloro che vengono qui per la prima volta, vorrei postare una soluzione. Ho un valore float indexe una stringa imgfilee ho avuto il tuo stesso problema. Ecco come ho risolto il problema

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

L'output è

1.0,data/2.jpg

È possibile modificare questo esempio di formattazione secondo la propria convenienza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.