-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
PEP 682: Format Specifier for Signed Zero #2295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
f8b927c
a6bf8f3
e1ad4f9
3fbc1f6
7a86237
6522671
beb801d
8a58924
8fd0dd7
138ff46
0aadde6
866094b
e1ae1fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| PEP: 682 | ||
| Title: Format Specifier for Signed Zero | ||
| Author: John Belmonte <john@neggie.net> | ||
| Sponsor: Mark Dickinson <dickinsm@gmail.com> | ||
| Discussions-To: | ||
| Status: Draft | ||
| Type: Standards Track | ||
| Content-Type: text/x-rst | ||
| Created: 29-Jan-2022 | ||
| Python-Version: 3.11 | ||
| Post-History: | ||
|
|
||
|
|
||
| Abstract | ||
| ======== | ||
|
|
||
| Though ``float`` and ``Decimal`` types can represent `signed zero`_, in many fields | ||
| of mathematics, negative zero is surprising or unwanted -- especially | ||
belm0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| in the context of displaying an (often rounded) numerical result. This PEP | ||
| proposes an extension to the `string format specification`_, allowing negative | ||
| zero to be normalized to positive zero. | ||
|
|
||
| .. _`signed zero`: https://en.wikipedia.org/wiki/Signed_zero | ||
| .. _`string format specification`: https://docs.python.org/3/library/string.html#formatstrings | ||
|
|
||
|
|
||
| Motivation | ||
| ========== | ||
|
|
||
| Here is negative zero: | ||
|
|
||
| .. code-block:: pycon | ||
|
|
||
| >>> x = -0. | ||
| >>> x | ||
| -0.0 | ||
|
|
||
| When formatting a number, negative zero can result from rounding. Assuming | ||
| the user's intention is truly to discard precision, the distinction between | ||
| negative and positive zero of the rounded result might be considered an | ||
| unwanted artifact: | ||
|
|
||
| .. code-block:: pycon | ||
|
|
||
| >>> for x in (.002, -.001, .060): | ||
| ... print(f'{x: .1f}') | ||
| 0.0 | ||
| -0.0 | ||
| 0.1 | ||
|
|
||
| There are various approaches to clearing the sign of a negative zero. It | ||
| can be achieved without a conditional by adding positive zero: | ||
|
|
||
| .. code-block:: pycon | ||
|
|
||
| >>> x = -0. | ||
| >>> x + 0. | ||
| 0.0 | ||
|
|
||
| To normalize negative zero when formatting, it is necessary to perform | ||
| a redundant (and error-prone) pre-rounding of the input: | ||
|
|
||
| .. code-block:: pycon | ||
|
|
||
| >>> for x in (.002, -.001, .060): | ||
| ... print(f'{round(x, 1) + 0.: .1f}') | ||
| 0.0 | ||
| 0.0 | ||
| 0.1 | ||
|
Comment on lines
+63
to
+69
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, this isn't ideal. It's a pythondotorg styling problem, I'd imagine - and hard to fix currently. A
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Grep shows only one other PEP using
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would it be "pycon", and not "python"? It seems like all of the other PEPs don't specify a language, so I think you're right in removing it.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Support for specifying languages was only added very recently (by adding Pygments to the requirements file) -- as a PEP editor I would strongly encourage explicitness in language as it makes reading PEPs easier with correctly highlighted code. A
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bit late now, sorry (I was invited to visit the SpaceX Starship production and launch site in Texas and thus was unavailable for the past week) but I can fully confirm everything @AA-Turner said, which was the basis of my initial implemented suggestion. In addition to the reasons he mentioned, being explicit about the language in the code block is also ensures the block will be highlighted correct regardless of what we decide to do in terms of the default syntax highlighter (none, auto, Python, etc). If
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you-- while we did revert the pycon block annotations for now, I agree that accurate block annotation is desirable and we'd like all the PEP documents to be doing that. Summary from the time of the decision (#2317 (comment)):
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but as I noted there, AFAIK all this is specific to the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have avoided this topic as I don't want to spark a discussion. My current opinion is we should leave implicit literal block syntax as it is in most places, but update all cases where the language is not Python. This opinion is subject to change several times per arbitrary time period. This probably means we wouldn't update to
another debate for another time ;) A
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I share this opinion as well, and am willing to help implement if and when the time comes for this, though I think it could be limited to not include withdrawn, superceded, and otherwise inactive PEPs. For new PEPs I would favor the |
||
|
|
||
| What we would like instead is a first-class option to normalize negative | ||
mdickinson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| zero, on top of everything else that numerical string formatting already | ||
| offers. | ||
belm0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| Rationale | ||
| ========= | ||
|
|
||
| There are use cases where negative zero is unwanted in formatted number | ||
| output -- arguably it's the more common case. Expanding the format | ||
belm0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| specification is the best way to support this because number formatting | ||
| already incorporates rounding, and the normalization of negative zero must | ||
| happen after rounding. | ||
|
|
||
| While it is possible to pre-round and normalize a number before formatting, | ||
| it's tedious and prone to error if the rounding doesn't precisely match | ||
| that of the format spec. Furthermore, functions that wrap formatting would | ||
| find themselves having to parse format specs to extract the precision | ||
| information. For example, consider how this utility for formatting | ||
| one-dimensional numerical arrays would be complicated by such pre-rounding: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| 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)}]" | ||
|
|
||
| The solution must be opt-in, because we can't change the behavior of | ||
| programs that may be expecting or relying on negative zero when formatting | ||
| numbers. | ||
|
|
||
| The proposed extension is intentionally ``[sign][z]`` rather than | ||
| ``[sign[z]]``. The default for ``sign`` (``-``) is not widely known or | ||
| explicitly written, so this avoids everyone having to learn it just to use | ||
| the ``z`` option. | ||
|
||
|
|
||
| While f-strings, built-in ``format``, and ``str.format()`` can access the | ||
| new option, %-formatting cannot. There is already precedent for not | ||
| extending %-formatting with new options, as was the case for the | ||
| ``,`` option (:pep:`378`). | ||
|
|
||
| To date, there doesn't appear to be other widely-used languages or libraries | ||
| providing such a formatting option for negative zero. However, the same | ||
| ``z`` option syntax and semantics has been `proposed for C++ std::format()`_. | ||
| While the proposal was withdrawn for C++20, a consensus proposal is promised | ||
| for C++23. (For what it's worth, the original `feature request`_ prompting | ||
| this PEP was argued without knowledge of the C++ proposal.) | ||
belm0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| .. _`proposed for C++ std::format()`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1496r2.pdf | ||
| .. _`feature request`: https://bugs.python.org/issue45995 | ||
|
|
||
|
|
||
| Specification | ||
| ============= | ||
|
|
||
| An optional, literal ``z`` is added to the | ||
| `Format Specification Mini-Language`_ following ``sign``: | ||
|
|
||
| .. code-block:: text | ||
|
|
||
| [[fill]align][sign][z][#][0][width][grouping_option][.precision][type] | ||
|
|
||
| where ``z`` is allowed for numerical types other than integer. Support for | ||
| ``z`` is provided by the ``__format__()`` method of each numeric type, | ||
belm0 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| allowing the specifier to be used in f-strings, built-in ``format()``, and | ||
| ``str.format()``. The %-formatting style will not support the new option. | ||
|
|
||
| Synopsis: | ||
|
|
||
| .. code-block:: pycon | ||
|
|
||
| >>> x = -.00001 | ||
| >>> f'{x:z.1f}' | ||
| '0.0' | ||
|
|
||
| >>> x = decimal.Decimal('-.00001') | ||
| >>> '{:+z.1f}'.format(x) | ||
| '+0.0' | ||
|
|
||
| .. _`Format Specification Mini-Language`: https://docs.python.org/3/library/string.html#format-specification-mini-language | ||
|
|
||
|
|
||
| Backwards Compatibility | ||
| ======================= | ||
|
|
||
| The new formatting behavior is opt-in, so numerical formatting of existing | ||
| programs will not be affected. | ||
|
|
||
|
|
||
| Reference Implementation | ||
| ======================== | ||
|
|
||
| A reference implementation exists at `pull request #30049`_. | ||
|
|
||
| .. _`pull request #30049`: https://github.com/python/cpython/pull/30049 | ||
|
|
||
|
|
||
| Copyright | ||
| ========= | ||
|
|
||
| This document is placed in the public domain or under the | ||
| CC0-1.0-Universal license, whichever is more permissive. | ||
|
|
||
|
|
||
|
|
||
| .. | ||
| Local Variables: | ||
| mode: indented-text | ||
| indent-tabs-mode: nil | ||
| sentence-end-double-space: t | ||
| fill-column: 70 | ||
| coding: utf-8 | ||
| End: | ||

Uh oh!
There was an error while loading. Please reload this page.