PythonCharmers/python-future

Exceptions from `round` implementation

Open

#322 opened on Jan 20, 2018

View on GitHub
 (0 comments) (0 reactions) (0 assignees)Python (1,172 stars) (327 forks)batch import
0.20bughelp wanted

Description

[Prompted by this StackOverflow question]

There are a couple of issues with the current implementation of round from builtins:

  • it doesn't support negative second argument:
>>> from builtins import round
>>> round(314, -2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/future/builtins/newround.py", line 33, in newround
    raise NotImplementedError('negative ndigits not supported yet')
NotImplementedError: negative ndigits not supported yet
  • it can raise decimal.InvalidOperation:
>>> round(1e50, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/future/builtins/newround.py", line 43, in newround
    rounding=ROUND_HALF_EVEN)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.py", line 2468, in quantize
    'quantize result has too many digits for current context')
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.py", line 3872, in _raise_error
    raise error(explanation)
decimal.InvalidOperation: quantize result has too many digits for current context

The first restriction seems unnecessary. The second can be overcome by using a dedicated decimal context with sufficient precision. For rounding a float x to n decimal places (with n possibly negative), I'd suggest something like the following:

from decimal import Context, Decimal
c = Context(prec=800)  # sufficient precision that the `quantize` result is representable
quantum = Decimal("1e{}".format(-n))  # should work for both n positive and negative
rounded = float(c.quantize(Decimal(x), quantum))

(The bound of 800 here is a bit crude. The maximum number of significant digits needed to represent any IEEE 754 binary64 float exactly in decimal is 767.)

Contributor guide