Gibt es einen einfachen Weg oder eine integrierte Funktion, um die Nachkommastellen einer Gleitkommazahl herauszufinden?
Die Zahl wird aus einer Zeichenfolge analysiert. Eine Möglichkeit besteht darin, die Ziffern nach dem '.' Zu zählen. Zeichen, aber das sieht für mich ziemlich ungeschickt aus. Gibt es eine Möglichkeit, die benötigten Informationen aus einem Objekt float
oder Decimal
abzurufen?
SOLUTION (einer von ihnen natürlich :))
Ich habe mich für die python decimal.Decimal-Klasse entschieden, um mir bei meinem Problem zu helfen:
e = abs(Decimal(string_value).as_Tuple().exponent)
HINWEIS: Dies funktioniert nur, wenn der Parameter, aus dem die Dezimalzahl erstellt wird, eine Zeichenfolge und kein Gleitkomma ist (was zu Gleitkommaungenauigkeiten führen würde).
Vielen Dank für alle anderen Beiträge.
Um zu wiederholen, was andere gesagt haben (weil ich es bereits abgetippt hatte!), Bin ich mir nicht einmal sicher, ob ein solcher Wert im Fall einer Gleitkommazahl aufgrund des Unterschieds zwischen der Dezimal- und der Binärdarstellung sinnvoll wäre. Oft hat eine Zahl, die durch eine endliche Anzahl von Dezimalstellen darstellbar ist, nur eine unendlich-stellige Darstellung in binärer Form.
Im Falle eines decimal.Decimal
Objekt können Sie den Exponenten mit dem as_Tuple
-Methode, die ein named-Tupel mit den Attributen sign
, digits
und exponent
zurückgibt:
>>> d = decimal.Decimal('56.4325')
>>> d.as_Tuple().exponent
-4
>>> d = decimal.Decimal('56.43256436')
>>> d.as_Tuple().exponent
-8
Die Negation des Exponenten ist die Anzahl der Nachkommastellen, es sei denn, der Exponent ist größer als 0
.
Ein naiver Weg (anfällig für die von @jglouie erwähnte lokalisierte Verwendung) ist
len(foo.split('.')[1])
wobei foo eine Zeichenfolge wie "23.512999238" ist.
Wie @Thomas Jung und @Mark Ransom bereits erwähnt haben, ist dies für einige Eckfälle eher naiv, die wie ...
import re
from locale import localeconv
dec_pt = localeconv()['decimal_point']
decrgx = re.compile("\d+(%s\d+)?e(-|\+)(\d+)" % dec_pt)
if decrgx.search(foo):
# still figuring this out
raise NotImplementedError, "e notation not implemented"
else:
digits = len(foo.split(dec_pt)[-1])
"Die Anzahl der Dezimalstellen" ist keine Eigenschaft einer Gleitkommazahl, da sie intern gespeichert und verarbeitet wird.
Sie können von einer Gleitkommazahl beliebig viele Nachkommastellen erhalten. Die Frage ist, wie viel Genauigkeit Sie wollen. Bei der Konvertierung einer Gleitkommazahl in einen String entscheidet ein Teil des Prozesses über die Genauigkeit.
Versuchen Sie zum Beispiel:
1.1 - int(1.1)
Und Sie werden sehen, dass die Antwort lautet:
0.10000000000000009
In diesem Fall beträgt die Anzahl der Dezimalstellen 17. Dies ist wahrscheinlich nicht die gesuchte Zahl.
Sie können die Zahl jedoch mit "round" auf eine bestimmte Anzahl von Dezimalstellen runden:
round(3.1415 - int(3.1415), 3)
In diesem Fall wird die Anzahl der Dezimalstellen auf 3 verringert.
Sie können nicht die Anzahl der Dezimalstellen eines Floats ermitteln, aber Sie können die Genauigkeit und die Anzahl der gewünschten Dezimalstellen bestimmen.
Das Umwandeln eines Floats in einen String ist eine Möglichkeit, eine solche Entscheidung zu treffen.
Die Dezimalbibliothek dient zum Arbeiten mit Dezimalzahlen wie im Rechnungswesen. Es hat von Natur aus keine Funktion, um die Anzahl der Dezimalstellen zurückzugeben. Dies ist insbesondere dann ein Problem, wenn Sie feststellen, dass der Kontext, unter dem er ausgeführt wird, den vom Benutzer gewünschten Wert angibt.
Wenn Sie eine Zeichenfolge erhalten, können Sie diese in eine Dezimalzahl konvertieren. Dabei werden jedoch entweder Nullen verwendet, um die Genauigkeit zu ermitteln, oder die Rundungseinstellung wird zum Abschneiden verwendet.
Ihre beste Wette würde wahrscheinlich auf den Punkt in Ihrer Zeichenfolge aufteilen und die Anzahl der Zeichen in der resultierenden Teilzeichenfolge zählen.
Wenn Sie wissen, dass Sie keine Parsing-Probleme haben werden (oder wenn Sie python selbst oder eine andere Bibliothek das für Sie erledigen lassen und hoffentlich Lokalisierungsprobleme lösen) ... analysieren Sie es einfach und benutze modf . Der Rückgabewert ist ein Paar von Werten, von denen einer der integrale Teil, der andere der gebrochene Teil ist.
Ich brauchte so etwas und testete einige davon. Das schnellste, was ich herausfand, war:
str(number)[::-1].find('.')
Wegen des Gleitkomma-Problems gaben mir alle Modulo-Werte sogar mit Dezimal (Zahl) falsche Ergebnisse (beachte, dass ich dies in einem Skript brauchte, um die Preise einer gesamten Datenbank zu bestimmen)
len(str(Decimal(str(number))) % Decimal(1))) - 2
Die Notwendigkeit, einen String in Decimal zu schreiben, ist ziemlich unangenehm, wenn wir Floats oder ähnliches haben.
Hier ist meine "Bank": https://repl.it/FM8m/17
Der schnellste Weg, den ich gefunden habe, um Nachkommastellen zu berechnen und die Zahl zu runden, ist
Ziffern berechnen:
a=decimal.Decimal('56.9554362669143476');
lenstr = len(str(a).split(".")[1])
Berechnen, prüfen und runden:
a=decimal.Decimal('56.9554362669143476');
a = round(float(a),5) if len(str(a).split(".")[1]) > 5 else float(a)
Vergleich:
$ python2 -mtimeit 'import decimal; a=decimal.Decimal('56.9554362669143476'); round(float(a),5) if a.as_Tuple().exponent < -5 else float(a)'
10000 loops, best of 3: 32.4 usec per loop
$ python -mtimeit 'import decimal; a=decimal.Decimal('56.9554362669143476'); a = round(float(a),5) if len(str(a).split(".")[1]) > 5 else float(a)'
100000 loops, best of 3: 16.7 usec per loop
Da Python Gleitkommazahlen intern nicht als Dezimalzahl, sondern als Binärzahl dargestellt werden, gibt es eigentlich keine andere Abkürzung als die Konvertierung in eine Dezimalzahl. Die einzige integrierte Möglichkeit, dies zu tun, ist die Konvertierung in eine Zeichenfolge. You Sie könnten Ihren eigenen Code schreiben, um eine Dezimalumwandlung durchzuführen und die Ziffern zu zählen, aber dies wäre eine doppelte Anstrengung.