Formatieren von Gleitkommazahlen ohne nachgestellte Nullen

Lesezeit: 9 Minuten

Benutzer-Avatar
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.

Zum Beispiel:

3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"

  • 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.

    – Scott Stafford

    11. Mai 2020 um 14:47 Uhr

Benutzer-Avatar
unutbu

Du könntest benutzen %g um das zu erreichen:

'%g'%(3.140)

oder mit Python ≥ 2.6:

'{0:g}'.format(3.140)

oder mit Python ≥ 3.6:

f'{3.140:g}'

Von dem Dokumente für format: g Ursachen (unter anderem)

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:

def floatToString(inputValue):
    return ('%.15f' % inputValue).rstrip('0').rstrip('.')

Meine Begründung:

%g wird die wissenschaftliche Notation nicht los.

>>> '%g' % 0.000035
'3.5e-05'

15 Dezimalstellen scheinen seltsames Verhalten zu vermeiden und haben viel Präzision für meine Bedürfnisse.

>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'

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().

>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')

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.

>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')

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.6 True

    – PolyMesh

    7. März 2019 um 0:26 Uhr


  • Ich habe eine andere Lösung geschrieben.

    – Niitsuma

    10. Juni 2020 um 3:27 Uhr

Benutzer-Avatar
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

Benutzer-Avatar
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

1053730cookie-checkFormatieren von Gleitkommazahlen ohne nachgestellte Nullen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy