PEP 682 – Format Specifier für Signed Zero
- Autor:
- John Belmonte <john at neggie.net>
- Sponsor:
- Mark Dickinson <dickinsm at gmail.com>
- PEP-Delegate:
- Mark Dickinson
- Discussions-To:
- Discourse thread
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 29-Jan-2022
- Python-Version:
- 3.11
- Post-History:
- 08-Feb-2022
- Resolution:
- Discourse thread
Zusammenfassung
Obwohl die Typen float und Decimal vorzeichenbehaftetes Null darstellen können, ist in vielen mathematischen Bereichen negatives Null überraschend oder unerwünscht – insbesondere im Kontext der Anzeige eines (oft gerundeten) numerischen Ergebnisses. Diese PEP schlägt eine Erweiterung der String-Format-Spezifikation vor, die es ermöglicht, negatives Null auf positives Null zu normalisieren.
Motivation
Hier ist negatives Null
>>> x = -0.
>>> x
-0.0
Beim Formatieren einer Zahl kann negatives Null durch Rundung entstehen. Unter der Annahme, dass die Absicht des Benutzers tatsächlich darin besteht, die Genauigkeit zu verwerfen, kann die Unterscheidung zwischen negativem und positivem Null des gerundeten Ergebnisses als unerwünschtes Artefakt betrachtet werden
>>> for x in (.002, -.001, .060):
... print(f'{x: .1f}')
0.0
-0.0
0.1
Es gibt verschiedene Ansätze, um das Vorzeichen von negativem Null zu löschen. Dies kann ohne Bedingung durch Hinzufügen von positivem Null erreicht werden
>>> x = -0.
>>> x + 0.
0.0
Um negatives Null beim Formatieren zu normalisieren, ist eine redundante (und fehleranfällige) Vorabrundung der Eingabe erforderlich
>>> for x in (.002, -.001, .060):
... print(f'{round(x, 1) + 0.: .1f}')
0.0
0.0
0.1
Es gibt zahlreiche Beweise dafür, dass Programmierer unabhängig von der Sprache oft nach einer Möglichkeit suchen, negatives Null zu unterdrücken, und auf eine Vielzahl von Workarounds stoßen (Vorabrundung, Post-Regex usw.). Eine Stichprobe
- Wie kann negatives Null in einem Python-String immer als positives Null formatiert werden? (Python, Post-Regex)
- (Iron)Python Formatierungsproblem mit Modulo-Operator und "negativem Null" (Python, Vorabrundung)
- Negatives Vorzeichen bei Null in Java (Java, Post-Regex)
- Verhindern, dass kleine negative Zahlen als "-0" gedruckt werden (Objective-C, benutzerdefinierter Zahlenformatierer)
Was wir stattdessen möchten, ist eine First-Class-Option zur Normalisierung von negativem Null, zusätzlich zu allem anderen, was die numerische String-Formatierung bereits bietet.
Begründung
Es gibt Anwendungsfälle, in denen negatives Null in der formatierten numerischen Ausgabe unerwünscht ist – wahrscheinlich ist es häufiger unerwünscht. Die Erweiterung der Format-Spezifikation ist der beste Weg, dies zu unterstützen, da die numerische Formatierung bereits Rundungen enthält und die Normalisierung von negativem Null nach der Rundung erfolgen muss.
Obwohl es möglich ist, eine Zahl vor der Formatierung vorzurunden und zu normalisieren, ist dies mühsam und fehleranfällig, wenn die Rundung nicht genau mit der der Format-Spezifikation übereinstimmt. Darüber hinaus müssten Funktionen, die die Formatierung umschließen, Format-Spezifikationen parsen, um die Präzisionsinformationen zu extrahieren. Betrachten Sie zum Beispiel, wie diese Dienstprogramm zur Formatierung eindimensionaler numerischer Arrays durch eine solche Vorabrundung kompliziert würde
def format_vector(v, format_spec='8.2f'):
"""Format a vector (any iterable) using given per-term format string."""
return f"[{','.join(f'{term:{format_spec}}' for term in v)}]"
Bis heute scheint es keine andere weit verbreitete Sprache oder Bibliothek zu geben, die eine Formatierungsoption für negatives Null bietet. Die gleiche z-Option-Syntax und Semantik, die unten spezifiziert sind, wurden jedoch für C++ std::format() vorgeschlagen. Obwohl der Vorschlag für C++20 zurückgezogen wurde, wird ein Konsensvorschlag für C++23 versprochen. (Die ursprüngliche Feature-Anfrage, die diese PEP veranlasste, wurde ohne Kenntnis des C++-Vorschlags argumentiert.)
Als Rust-Entwickler diskutierten, ob negatives Null in der print-Ausgabe unterdrückt werden soll, führten sie eine kleine Umfrage in anderen Sprachen durch. Bemerkenswert ist, dass keine Sprache mit einer Option für die Handhabung von negativem Null erwähnt wurde.
Spezifikation
Ein optionales, literales z wird der Format Specification Mini-Language nach sign hinzugefügt
[[fill]align][sign][z][#][0][width][grouping_option][.precision][type]
wobei z für Gleitkomma-Darstellungstypen (f, g usw. gemäß der Dokumentation der Format-Spezifikation) zulässig ist. Unterstützung für z wird durch die Methode .__format__() jedes numerischen Typs bereitgestellt, sodass der Spezifizierer in f-Strings, der integrierten Funktion format() und str.format() verwendet werden kann.
Wenn z vorhanden ist, wird negatives Null (egal ob der ursprüngliche Wert oder das Ergebnis der Rundung) auf positives Null normalisiert.
Zusammenfassung
>>> x = -.00001
>>> f'{x:z.1f}'
'0.0'
>>> x = decimal.Decimal('-.00001')
>>> '{:+z.1f}'.format(x)
'+0.0'
Design Notes
Die Lösung muss opt-in sein, da wir das Verhalten von Programmen, die möglicherweise auf negatives Null beim Formatieren von Zahlen angewiesen sind oder darauf vertrauen, nicht ändern können.
Die vorgeschlagene Erweiterung ist bewusst [sign][z] und nicht [sign[z]]. Der Standard für sign (-) ist nicht allgemein bekannt oder explizit geschrieben, daher vermeidet dies, dass jeder ihn lernen muss, nur um die Option z zu verwenden.
Obwohl f-Strings, die integrierte Funktion format() und str.format() auf die neue Option zugreifen können, kann dies die %-Formatierung nicht. Es gibt bereits Präzedenzfälle für die Nicht-Erweiterung der %-Formatierung mit neuen Optionen, wie es bei der Option , der Fall war (PEP 378).
C99 printf verwendet bereits das Zeichen der Option z für einen anderen Zweck: die Qualifizierung des vorzeichenlosen Typs (u), um der Länge von size_t zu entsprechen. Da die Option für vorzeichenloses Null jedoch z für Ganzzahl-Darstellungstypen explizit verbietet, ist es möglich, die beiden Verwendungen zu disambiguieren, falls C diese neue Option übernehmen möchte.
Abwärtskompatibilität
Das neue Formatierungsverhalten ist opt-in, sodass die numerische Formatierung bestehender Programme nicht beeinträchtigt wird.
Wie man das lehrt
Ein typischer einführender Python-Kurs behandelt die String-Formatierung nicht im Detail. Für einen solchen Kurs müssten keine Anpassungen vorgenommen werden. Für einen Kurs, der sich detailliert mit der String-Format-Spezifikation befasst, sollte ein einzelnes Beispiel, das die Auswirkung der Option z auf einen negativen Wert zeigt, der durch die Formatierung auf Null gerundet wird, ausreichen. Für einen unabhängigen Entwickler, der die Funktion in fremdem Code antrifft, sollte ein Verweis auf den Abschnitt Format Specification Mini-Language des Bibliotheksreferenzhandbuchs genügen.
Referenzimplementierung
Eine Referenzimplementierung existiert unter Pull Request #30049.
Urheberrecht
Dieses Dokument wird in die Public Domain oder unter die CC0-1.0-Universal-Lizenz gestellt, je nachdem, welche Lizenz permissiver ist.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0682.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT