Formatieren von Gleitkommazahlen ohne nachgestellte Nullen
Lesezeit: 9 Minuten
TarGz
Wie kann ich einen Float so formatieren, dass er keine nachgestellten Nullen enthält? Mit anderen Worten, ich möchte, dass die resultierende Zeichenfolge so kurz wie möglich ist.
Das Beispiel macht überhaupt keinen Sinn. 3.14 == 3.140 – Sie sind die gleich Fließkommazahl. Übrigens ist 3.140000 die gleiche Fließkommazahl. Die Null existiert gar nicht.
– S. Lott
14. März 2010 um 1:08 Uhr
@S.Lott – Ich denke, das Problem besteht darin, die Gleitkommazahl ohne die nachgestellten Nullen zu drucken, nicht die tatsächliche Äquivalenz zweier Zahlen.
– Pokstad
14. März 2010 um 1:14 Uhr
@pokstad: In diesem Fall gibt es keine “überflüssige” Null. %0.2f und %0.3f sind die beiden Formate, die erforderlich sind, um die letzten Zahlen auf der linken Seite zu erzeugen. Verwenden %0.2f um die letzten beiden Zahlen auf der rechten Seite zu erzeugen.
– S. Lott
14. März 2010 um 1:16 Uhr
3.0 -> "3" ist immer noch ein gültiger Anwendungsfall. print( '{:,g}'.format( X ) hat für mich funktioniert, um auszugeben 3 wo X = 6 / 2 und wann X = 5 / 2 Ich habe eine Ausgabe von 2.5 wie erwartet.
– Schuhmacher
27. Februar 2016 um 23:51 Uhr
alte Frage, aber.. print("%s"%3.140) gibt dir was du willst. (Ich habe unten eine Antwort hinzugefügt …)
– Dreviko
5. April 2018 um 11:55 Uhr
Ich würde es tun ('%f' % x).rstrip('0').rstrip('.') — garantiert Festkommaformatierung statt wissenschaftlicher Notation usw. Ja, nicht so glatt und elegant wie %gaber es funktioniert (und ich weiß nicht, wie man es erzwingt %g niemals die wissenschaftliche Schreibweise zu verwenden;-).
Das einzige Problem dabei ist '%.2f' % -0.0001 wird dich verlassen -0.00 und ultimativ -0.
– Kos
7. Dezember 2012 um 13:14 Uhr
@alexanderlukanin13 weil die Standardpräzision 6 ist, siehe docs.python.org/2/library/string.html: 'f' Fixed point. Displays the number as a fixed-point number. The default precision is 6. Sie müssten in der obigen Lösung ‘%0.7f’ verwenden.
– derenio
31. August 2015 um 16:55 Uhr
@derenio Guter Punkt 🙂 Ich kann diese Erhöhungspräzision nur oben hinzufügen '%0.15f' ist eine schlechte Idee, weil Komisches Zeug beginnt zu passieren.
– Alexanderlukanin13
1. September 2015 um 15:38 Uhr
Falls Sie sich mitten in einer anderen Zeichenfolge befinden: print('In the middle {} and something else'.format('{:f}'.format(a).rstrip('0')))
– Fehlertoleranz
28. April 2018 um 8:10 Uhr
@Peter Schorn: Sie haben Recht, dass die Optimierung von Gabriel Staples schlecht ist, aber der Trick des OP erfordert, dass Sie alle Nullen, DANN alle Dezimalstellen und dann NICHT MEHR NULLEN entfernen. Gabriels Ansatz entfernt einfach alle Nullen und Punkte, bis er auf etwas anderes trifft.
unbedeutende nachgestellte Nullen [to be]
von der Mantisse entfernt, und der Dezimalpunkt wird ebenfalls entfernt, wenn keine verbleibenden Ziffern darauf folgen.
Ach, fast! Manchmal formatiert es den Float in wissenschaftlicher Notation (“2.342E+09”) – ist es möglich, es auszuschalten, dh immer alle signifikanten Ziffern anzuzeigen?
– TarGz
14. März 2010 um 0:46 Uhr
Warum verwenden '{0:...}'.format(value) wann du es gebrauchen könntest format(value, '...')? Dadurch wird vermieden, den Formatbezeichner aus einer ansonsten leeren Vorlagenzeichenfolge herauszuparsen.
– Martijn Pieters ♦
11. August 2016 um 9:00 Uhr
@MartijnPieters: Die winzigen Kosten für das Analysieren des Formatbezeichners werden durch andere Overhead-AFAICT überschwemmt. In der Praxis haben meine lokalen Benchmarks auf 3.6 (mit Funktionsumfang des Microbenchmarks, um realen Code genau zu modellieren) zu haben format(v, '2.5f') ~10% länger dauern als '{:2.5f}'.format(v). Selbst wenn nicht, neige ich dazu, die zu verwenden str Methodenform, denn wenn ich es optimieren, zusätzliche Werte hinzufügen usw. muss, gibt es weniger zu ändern. Ab Version 3.6 haben wir natürlich f-Saiten für die meisten Zwecke. 🙂
– ShadowRanger
25. August 2018 um 2:12 Uhr
In Python 3.6 kann dies verkürzt werden auf f"{var:g}" wo var ist eine Float-Variable.
– Der Große Kohl
24. September 2019 um 15:15 Uhr
@TarGz: Ich hatte Erfolg mit '%d'%numpy.rint(my_number). Im Grunde rundet es die Zahl mit numpy auf die nächste ganze Zahl rint Methode (Sie könnten verwenden round auch) und druckt es dann mit einem int-Flag (%d). Du könntest benutzen '%d'%my_number direkt, aber dann würde es die Zahl abrunden, anstatt auf die nächste zu runden.
– Johannes Lemonde
10. November 2021 um 13:47 Uhr
Nachdem ich die Antworten auf mehrere ähnliche Fragen durchgesehen habe, scheint dies die beste Lösung für mich zu sein:
hätte ich gebrauchen können format(inputValue, '.15f'). Anstatt von '%.15f' % inputValueaber das ist etwas langsamer (~30%).
hätte ich gebrauchen können Decimal(inputValue).normalize(), aber das hat auch ein paar Probleme. Zum einen ist es VIEL langsamer (~11x). Ich fand auch, dass es, obwohl es eine ziemlich große Präzision hat, bei der Verwendung immer noch unter Präzisionsverlust leidet normalize().
Am wichtigsten wäre, ich würde immer noch konvertieren Decimal von einem float was dazu führen kann, dass Sie am Ende etwas anderes als die Zahl haben, die Sie dort eingegeben haben. Ich finde Decimal funktioniert am besten, wenn die Arithmetik drin bleibt Decimal und die Decimal wird mit einem String initialisiert.
Ich bin mir sicher, das Problem der Präzision Decimal.normalize() kann mithilfe der Kontexteinstellungen an die Anforderungen angepasst werden, aber in Anbetracht der ohnehin langsamen Geschwindigkeit und der Notwendigkeit, keine lächerliche Präzision zu benötigen, und der Tatsache, dass ich immer noch von einem Float konvertieren und die Präzision sowieso verlieren würde, hielt ich es nicht für wert, weiterverfolgt zu werden.
Ich mache mir keine Sorgen um das mögliche “-0” -Ergebnis, da -0.0 eine gültige Gleitkommazahl ist und wahrscheinlich sowieso selten vorkommt, aber da Sie erwähnt haben, dass Sie das Zeichenfolgenergebnis so kurz wie möglich halten möchten, Sie könnte immer eine zusätzliche Bedingung zu sehr geringen zusätzlichen Geschwindigkeitskosten verwenden.
def floatToString(inputValue):
result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
return '0' if result == '-0' else result
Funktioniert leider nur bei Zahlen mit weniger als ungefähr fünf oder mehr Stellen links vom Komma. floatToString(12345.6) kehrt zurück '12345.600000000000364' zum Beispiel. Verringerung der 15 Zoll %.15f zu einer niedrigeren Zahl löst es in diesem Beispiel, aber dieser Wert muss immer weiter verringert werden, wenn die Zahl größer wird. Sie könnte basierend auf der logarithmischen Basis 10 der Zahl dynamisch berechnet werden, aber das wird schnell sehr kompliziert.
– JohnSpeeks
29. März 2017 um 3:21 Uhr
Eine Möglichkeit, dieses Problem zu lösen, könnte darin bestehen, die Länge der ganzen Zahl zu begrenzen (und nicht nur die Ziffern nach dem Komma): result = ('%15f' % val).rstrip('0').rstrip('.').lstrip(' ')
– Timothy Smith
6. Juli 2018 um 17:08 Uhr
@JohnSpeeks Ich bin mir nicht sicher, ob dies vermeidbar ist. Es ist ein Nebeneffekt, dass Gleitkommazahlen die Genauigkeit nicht darstellen können, wenn mehr Ziffern auf der linken Seite benötigt werden. Soweit ich das beurteilen kann, ist die Zahl, die als String herauskommt, die gleiche Zahl, die als Float hineingeht, oder zumindest die nächste Darstellung davon. >>>12345.600000000000364 == 12345.6True
– PolyMesh
7. März 2019 um 0:26 Uhr
Ich habe eine andere Lösung geschrieben.
– Niitsuma
10. Juni 2020 um 3:27 Uhr
Anders
Wie wäre es mit dem einfachsten und wahrscheinlich effektivsten Ansatz? Die Methode normalisieren() entfernt alle abschließenden Nullen ganz rechts.
from decimal import Decimal
print (Decimal('0.001000').normalize())
# Result: 0.001
Arbeitet in Python 2 und Python 3.
— Aktualisiert —
Das einzige Problem, wie @BobStein-VisiBone betonte, ist, dass Zahlen wie 10, 100, 1000 … in Exponentialdarstellung angezeigt werden. Dies kann stattdessen einfach mit der folgenden Funktion behoben werden:
from decimal import Decimal
def format_float(f):
d = Decimal(str(f));
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
Hier ist eine Lösung, die für mich funktioniert hat. Es ist eine Mischung aus der Lösung von PolyMesh und Nutzung des Neuen .format()Syntax.
for num in 3, 3., 3.0, 3.1, 3.14, 3.140:
print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))
Ausgabe:
3
3
3
3.1
3.14
3.14
Das einzige, was hier falsch ist, ist, dass Sie eine vernünftige Anzahl von Dezimalstellen einstellen müssen. Je höher Sie es einstellen, desto genauere Zahlen können Sie darstellen, aber wenn Sie dies häufig tun, kann dies die Leistung beeinträchtigen.
– beruic
29. Juni 2017 um 12:10 Uhr
Ergänzend zu Beruics Kommentar funktioniert dies nicht für Gleitkommazahlen mit größerer Genauigkeit (z 3.141) als die .2f ist fest codiert.
– TrebledJ
6. Juni 2019 um 5:47 Uhr
result = “{:. {}f}”.format(float(format(number).rstrip(‘0’).rstrip(‘.’)), precision), behebt dieses Problem TrebledJ.
– Kris Kizlyk
5. März 2021 um 6:17 Uhr
ideal für eine One-Liner-One-Use-Anwendung ohne zusätzliche Bibliotheken
– Paul Collingwood
25. April 2021 um 11:28 Uhr
clel
Sie können einfach format() verwenden, um dies zu erreichen:
format(3.140, '.10g') wobei 10 die gewünschte Genauigkeit ist.
Das einzige, was hier falsch ist, ist, dass Sie eine vernünftige Anzahl von Dezimalstellen einstellen müssen. Je höher Sie es einstellen, desto genauere Zahlen können Sie darstellen, aber wenn Sie dies häufig tun, kann dies die Leistung beeinträchtigen.
– beruic
29. Juni 2017 um 12:10 Uhr
Ergänzend zu Beruics Kommentar funktioniert dies nicht für Gleitkommazahlen mit größerer Genauigkeit (z 3.141) als die .2f ist fest codiert.
– TrebledJ
6. Juni 2019 um 5:47 Uhr
result = “{:. {}f}”.format(float(format(number).rstrip(‘0’).rstrip(‘.’)), precision), behebt dieses Problem TrebledJ.
– Kris Kizlyk
5. März 2021 um 6:17 Uhr
ideal für eine One-Liner-One-Use-Anwendung ohne zusätzliche Bibliotheken
– Paul Collingwood
25. April 2021 um 11:28 Uhr
Während die Formatierung wahrscheinlich die pythonischste Art ist, ist hier eine alternative Lösung mit der more_itertools.rstrip Werkzeug.
import more_itertools as mit
def fmt(num, pred=None):
iterable = str(num)
predicate = pred if pred is not None else lambda x: x in {".", "0"}
return "".join(mit.rstrip(iterable, predicate))
assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"
Die Zahl wird in eine Zeichenfolge konvertiert, die von nachgestellten Zeichen befreit wird, die ein Prädikat erfüllen. Die Funktionsdefinition fmt ist nicht erforderlich, wird aber hier verwendet, um Behauptungen zu testen, die alle bestehen. Hinweis: Es funktioniert mit Zeichenfolgeneingaben und akzeptiert optionale Prädikate.
Siehe auch Details zu dieser Drittanbieter-Bibliothek, more_itertools.
Die meisten Lösungen hier (einschließlich dieser) vergessen Ganzzahlen, die auf 0 enden, was ein unerwünschtes Verhalten ist.
– Benutzer222758
12. September 2021 um 4:30 Uhr
10537300cookie-checkFormatieren von Gleitkommazahlen ohne nachgestellte Nullenyes
Das Beispiel macht überhaupt keinen Sinn.
3.14 == 3.140
– Sie sind die gleich Fließkommazahl. Übrigens ist 3.140000 die gleiche Fließkommazahl. Die Null existiert gar nicht.– S. Lott
14. März 2010 um 1:08 Uhr
@S.Lott – Ich denke, das Problem besteht darin, die Gleitkommazahl ohne die nachgestellten Nullen zu drucken, nicht die tatsächliche Äquivalenz zweier Zahlen.
– Pokstad
14. März 2010 um 1:14 Uhr
@pokstad: In diesem Fall gibt es keine “überflüssige” Null.
%0.2f
und%0.3f
sind die beiden Formate, die erforderlich sind, um die letzten Zahlen auf der linken Seite zu erzeugen. Verwenden%0.2f
um die letzten beiden Zahlen auf der rechten Seite zu erzeugen.– S. Lott
14. März 2010 um 1:16 Uhr
3.0 -> "3"
ist immer noch ein gültiger Anwendungsfall.print( '{:,g}'.format( X )
hat für mich funktioniert, um auszugeben3
woX = 6 / 2
und wannX = 5 / 2
Ich habe eine Ausgabe von2.5
wie erwartet.– Schuhmacher
27. Februar 2016 um 23:51 Uhr
alte Frage, aber..
print("%s"%3.140)
gibt dir was du willst. (Ich habe unten eine Antwort hinzugefügt …)– Dreviko
5. April 2018 um 11:55 Uhr