Frage

Ich bin ein Python-Skript beibehalten wird, dass Anwendungen xlrd von Excel-Tabellen abgerufen werden Werte, und dann verschiedene Dinge zu tun mit ihnen. Einige der Zellen in der Tabelle sind hochpräzise Zahlen, und sie müssen als solche bleiben. Wenn die Werte einer dieser Zellen Abrufen xlrd gibt mir ein float wie ,38288746115497402.

Ich brauche aber später diesen Wert in einen String erhalten im Code. Doing entweder str(value) oder unicode(value) wird wieder so etwas wie „,382887461155“. Die Anforderungen sagen, dass dies nicht akzeptabel ist; die Präzision muss bewahrt werden.

Ich habe ein paar Dinge ausprobiert bisher ohne Erfolg. Das war zunächst eine Zeichenfolge mit der Formatierung Dingen:

data = "%.40s" % (value) 
data2 = "%.40r" % (value) 

Aber beide Produkte die gleiche abgerundete Zahl „,382887461155“.

Nach dem für Menschen mit ähnlichen Problemen auf SO suchen um und an anderer Stelle im Internet, war ein gemeinsamer Vorschlag, die Decimal Klasse zu verwenden. Aber ich kann nicht die Art und Weise ändern, die Daten, die mir gegeben ist (es sei denn, jemand von einem geheimen Weg kennt xlrd Rückkehr Decimals zu machen). Und wenn ich versuche, dies zu tun:

data = Decimal(value)

ich eine TypeError: Cannot convert float to Decimal. First convert the float to a string. bekommen Aber natürlich kann ich es nicht in eine Zeichenfolge konvertieren, sonst werde ich die Präzision verlieren.

Also ja, ich bin offen für alle Vorschläge - auch wirklich gross / Hacky diese bei Bedarf. Ich bin schrecklich nicht mit Python (mehr von einem Java / C # Kerl selbst) erfahren so fühlen sich frei, mich zu korrigieren, wenn ich hier eine Art von grundlegendem Missverständnis habe.

EDIT: Ich dachte, ich möchte hinzufügen, dass ich Python bin mit 2.6.4. Ich glaube nicht, gibt es keine formalen Anforderungen mich stoppen Versionen zu ändern; es muss nur nicht vermasseln einem anderen Code.

War es hilfreich?

Lösung

Ich bin der Autor von xlrd. Es gibt so viel Verwirrung in anderen Antworten und Kommentare in den Kommentaren zu entkräften, damit ich es in einer Antwort tue.

@katriealex: „“ „Präzision in den Eingeweiden von xlrd verloren“ „“ --- völlig unbegründet und unwahr. xlrd reproduziert genau die 64-Bit-Float, die in der XLS-Datei gespeichert wird.

@katriealex: „“ „Es möglich sein kann, Ihre lokale xlrd Installation zu ändern, um den Schwimmer Guss zu ändern“ „“ --- ich weiß nicht, warum Sie dies tun wollen; Sie verlieren keine Präzision durch eine 16-Bit-Integer-Floating !!! In jedem Fall, dass Code nur dann verwendet wird, wenn das Lesen Excel 2.X-Dateien (die einen Integer-Zelle Rekord hatten). Die OP gibt keinen Hinweis darauf, dass er solche alte Dateien liest.

@jloubert: Sie müssen verwechselt werden. "%.40r" % a_float ist nur eine barocke Art und Weise, die gleiche Antwort wie repr(a_float) bekommen.

@EVERYBODY: Sie brauchen nicht einen Schwimmer in eine Dezimalzahl zu konvertieren, die Genauigkeit zu erhalten. Der ganze Sinn der repr() Funktion ist, dass die folgende ist garantiert:

float(repr(a_float)) == a_float

Python 2.x (X <= 6) repr gibt einem konstanten 17 Dezimalstellen Präzision, wie garantiert wird, um den ursprünglichen Wert zu reproduzieren. Später Pythons (2.7, 3.1), um die minimale Anzahl von Dezimalstellen geben, die den ursprünglichen Wert reproduzieren.

Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.38288746115497402'
>>> float(repr(f)) == f
True

Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.382887461154974'
>>> float(repr(f)) == f
True

So lautet das Fazit ist, dass , wenn Sie eine Zeichenfolge, die bewahrt alle die Präzision eines Schwimmers Objekt, Verwendung preserved = repr(the_float_object) ... später den Wert wiederherstellen, indem float(preserved). Es ist so einfach. Keine Notwendigkeit für die decimal Modul.

Andere Tipps

Sie können repr() zu konvertieren in eine Zeichenfolge verwenden, ohne Präzision zu verlieren, dann umwandeln in eine Dezimal:

>>> from decimal import Decimal
>>> f = 0.38288746115497402
>>> d = Decimal(repr(f))
>>> print d
0.38288746115497402

EDIT: Ich bin falsch. Ich werde diese Antwort hier lassen, damit der Rest des Fadens Sinn macht, aber es ist nicht wahr. Bitte beachten Sie John Machin Antwort oben. Danke Jungs =).

Wenn die oben genannten Antworten arbeiten, das ist toll - es wird Ihnen eine Menge bösen Hacking speichern. Aber zumindest auf meinem System, werden sie nicht. Sie können dies mit z.

import sys
print( "%.30f" % sys.float_info.epsilon )

Diese Zahl ist der kleinste Schwimmer, dass Ihr System von Null unterscheiden kann. Alles, was kleiner ist als diejenige sein kann zufällig hinzugefügt oder von jedem Schwimmer abgezogen, wenn Sie eine Operation durchführen. Dies bedeutet, dass zumindest auf meinem Python-Setup, die Präzision in den Eingeweiden von xlrd verloren, und es scheint nichts zu sein Sie können es ohne Änderung zu tun. Das ist seltsam; Ich hätte dieser Fall zu erwarten, bevor aufgetreten sein, aber anscheinend nicht!

Es kann möglich sein, Ihre lokale xlrd Installation zu ändern, um die float Besetzung zu ändern. Aufmachen site-packages\xlrd\sheet.py und gehen Sie auf Linie 1099:

...
elif rc == XL_INTEGER:
                    rowx, colx, cell_attr, d = local_unpack('<HH3sH', data)
                    self_put_number_cell(rowx, colx, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
...

Beachten Sie die float cast -. Sie könnten versuchen, zu ändern, dass ein decimal.Decimal zu und sehen, was passiert

EDIT:. Gelöscht meine Antwort b / c es nicht richtig funktioniert

Ich bin auf Python 2.6.5 und das funktioniert für mich:

a = 0.38288746115497402
print repr(a)
type(repr(a))    #Says it's a string

Hinweis: Diese nur konvertiert in einen String. Sie werden konvertieren müssen, um sie später Decimal, wenn nötig.

Wie bereits gesagt wurde, ein Schwimmer überhaupt nicht präzise ist -. So Präzision bewahren kann etwas irreführend

Hier ist ein Weg, um jeden letzte Information aus einem Float-Objekt zu erhalten:

>>> from decimal import Decimal
>>> str(Decimal.from_float(0.1))
'0.1000000000000000055511151231257827021181583404541015625'

Eine andere Möglichkeit, wie so sein würde.

>>> 0.1.hex()
'0x1.999999999999ap-4'

Die beiden Strings repräsentieren den genauen Inhalt des Schwimmers. Allmost etwas anderes interpretiert der Schwimmer als Python denkt, dass es wohl gedacht war (die meiste Zeit richtig ist).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top