Konwersja pływaka na łańcuch bez zaokrąglania go


88

Tworzę program, który z powodów, których nie trzeba wyjaśniać, wymaga konwersji typu float na ciąg znaków do policzenia za pomocą len (). Jednak str (float (x)) powoduje, że x jest zaokrąglane po konwersji na łańcuch, co odrzuca całość. Czy ktoś wie, jak to naprawić? Oto kod używany, jeśli chcesz wiedzieć:

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

2
jeśli x jest pierwotnie str, dlaczego rzut?
Vinko Vrsalovic

1
-1: brak przykładów wymagany wynik dla różnych wartości x. Bez przykładów możemy tylko zgadywać, na czym polega problem.
S.Lott

Odpowiedzi:


128

W przypadku liczb zmiennoprzecinkowych często nie można uniknąć pewnych form zaokrąglania. Dzieje się tak, ponieważ liczby, które możesz wyrazić dokładnie w podstawie 10, nie zawsze mogą być wyrażone dokładnie w podstawie 2 (której używa twój komputer).

Na przykład:

>>> .1
0.10000000000000001

W tym przypadku widzisz .1 przekonwertowane na ciąg przy użyciu repr:

>>> repr(.1)
'0.10000000000000001'

Uważam, że Python odcina kilka ostatnich cyfr, gdy używasz str (), aby obejść ten problem, ale jest to częściowe obejście, które nie zastępuje zrozumienia, co się dzieje.

>>> str(.1)
'0.1'

Nie jestem pewien, jakie problemy powodują „zaokrąglanie”. Być może lepiej by było, gdyby formatowanie napisów było sposobem na dokładniejszą kontrolę wyników?

na przykład

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

Dokumentacja tutaj .


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

Muszę jednak powiedzieć, że nie jest to tak wiarygodne, jak myślisz.

Liczba zmiennoprzecinkowa jest wprowadzana / wyświetlana jako liczby dziesiętne, ale Twój komputer (w rzeczywistości Twoja standardowa biblioteka C) przechowuje je jako binarne. To przejście daje pewne efekty uboczne:

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

Wyjaśnienie, dlaczego tak się dzieje, znajduje się w tym rozdziale samouczka Pythona.

Rozwiązaniem byłoby użycie typu, który specjalnie śledzi liczby dziesiętne, na przykład w języku Python decimal.Decimal:

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

Dobry post dotyczący pracy z float wynika z podziału: stackoverflow.com/questions/2958684/python-division
Trutane

3

Inne odpowiedzi już wskazywały, że reprezentacja liczb zmiennoprzecinkowych jest co najmniej drażliwą kwestią.

Ponieważ nie podajesz wystarczającego kontekstu w swoim pytaniu, nie mogę wiedzieć, czy moduł dziesiętny może być przydatny dla Twoich potrzeb:

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

Między innymi możesz wyraźnie określić dokładność, którą chcesz uzyskać (z dokumentów):

>>> 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')

Prosty przykład z mojego znaku zachęty (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

Może to może pomóc? decimal jest w pythonie stdlib od 2.4, z dodatkami w pythonie 2.6.

Mam nadzieję, że to pomoże, Francesco


0

Wiem, że jest już za późno, ale dla tych, którzy przyjeżdżają tu po raz pierwszy, chciałbym zamieścić rozwiązanie. Mam wartość zmiennoprzecinkową indexi ciąg znaków imgfilei miałem ten sam problem co Ty. W ten sposób rozwiązałem problem

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

Wynik jest

1.0,data/2.jpg

Możesz zmodyfikować ten przykład formatowania według własnego uznania.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.