Index: third_party/google-endpoints/future/builtins/newround.py |
diff --git a/third_party/google-endpoints/future/builtins/newround.py b/third_party/google-endpoints/future/builtins/newround.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f59b35b325f74d06da0b45e5d3ff85b14a896c11 |
--- /dev/null |
+++ b/third_party/google-endpoints/future/builtins/newround.py |
@@ -0,0 +1,99 @@ |
+""" |
+``python-future``: pure Python implementation of Python 3 round(). |
+""" |
+ |
+from future.utils import PYPY, PY26, bind_method |
+ |
+# Use the decimal module for simplicity of implementation (and |
+# hopefully correctness). |
+from decimal import Decimal, ROUND_HALF_EVEN |
+ |
+ |
+def newround(number, ndigits=None): |
+ """ |
+ See Python 3 documentation: uses Banker's Rounding. |
+ |
+ Delegates to the __round__ method if for some reason this exists. |
+ |
+ If not, rounds a number to a given precision in decimal digits (default |
+ 0 digits). This returns an int when called with one argument, |
+ otherwise the same type as the number. ndigits may be negative. |
+ |
+ See the test_round method in future/tests/test_builtins.py for |
+ examples. |
+ """ |
+ return_int = False |
+ if ndigits is None: |
+ return_int = True |
+ ndigits = 0 |
+ if hasattr(number, '__round__'): |
+ return number.__round__(ndigits) |
+ |
+ if ndigits < 0: |
+ raise NotImplementedError('negative ndigits not supported yet') |
+ exponent = Decimal('10') ** (-ndigits) |
+ |
+ if PYPY: |
+ # Work around issue #24: round() breaks on PyPy with NumPy's types |
+ if 'numpy' in repr(type(number)): |
+ number = float(number) |
+ |
+ if not PY26: |
+ d = Decimal.from_float(number).quantize(exponent, |
+ rounding=ROUND_HALF_EVEN) |
+ else: |
+ d = from_float_26(number).quantize(exponent, rounding=ROUND_HALF_EVEN) |
+ |
+ if return_int: |
+ return int(d) |
+ else: |
+ return float(d) |
+ |
+ |
+### From Python 2.7's decimal.py. Only needed to support Py2.6: |
+ |
+def from_float_26(f): |
+ """Converts a float to a decimal number, exactly. |
+ |
+ Note that Decimal.from_float(0.1) is not the same as Decimal('0.1'). |
+ Since 0.1 is not exactly representable in binary floating point, the |
+ value is stored as the nearest representable value which is |
+ 0x1.999999999999ap-4. The exact equivalent of the value in decimal |
+ is 0.1000000000000000055511151231257827021181583404541015625. |
+ |
+ >>> Decimal.from_float(0.1) |
+ Decimal('0.1000000000000000055511151231257827021181583404541015625') |
+ >>> Decimal.from_float(float('nan')) |
+ Decimal('NaN') |
+ >>> Decimal.from_float(float('inf')) |
+ Decimal('Infinity') |
+ >>> Decimal.from_float(-float('inf')) |
+ Decimal('-Infinity') |
+ >>> Decimal.from_float(-0.0) |
+ Decimal('-0') |
+ |
+ """ |
+ import math as _math |
+ from decimal import _dec_from_triple # only available on Py2.6 and Py2.7 (not 3.3) |
+ |
+ if isinstance(f, (int, long)): # handle integer inputs |
+ return Decimal(f) |
+ if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float |
+ return Decimal(repr(f)) |
+ if _math.copysign(1.0, f) == 1.0: |
+ sign = 0 |
+ else: |
+ sign = 1 |
+ n, d = abs(f).as_integer_ratio() |
+ # int.bit_length() method doesn't exist on Py2.6: |
+ def bit_length(d): |
+ if d != 0: |
+ return len(bin(abs(d))) - 2 |
+ else: |
+ return 0 |
+ k = bit_length(d) - 1 |
+ result = _dec_from_triple(sign, str(n*5**k), -k) |
+ return result |
+ |
+ |
+__all__ = ['newround'] |