comparison env/lib/python3.7/site-packages/future/builtins/newround.py @ 2:6af9afd405e9 draft

"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author shellac
date Thu, 14 May 2020 14:56:58 -0400
parents 26e78fe6e8c4
children
comparison
equal deleted inserted replaced
1:75ca89e9b81c 2:6af9afd405e9
1 """
2 ``python-future``: pure Python implementation of Python 3 round().
3 """
4
5 from future.utils import PYPY, PY26, bind_method
6
7 # Use the decimal module for simplicity of implementation (and
8 # hopefully correctness).
9 from decimal import Decimal, ROUND_HALF_EVEN
10
11
12 def newround(number, ndigits=None):
13 """
14 See Python 3 documentation: uses Banker's Rounding.
15
16 Delegates to the __round__ method if for some reason this exists.
17
18 If not, rounds a number to a given precision in decimal digits (default
19 0 digits). This returns an int when called with one argument,
20 otherwise the same type as the number. ndigits may be negative.
21
22 See the test_round method in future/tests/test_builtins.py for
23 examples.
24 """
25 return_int = False
26 if ndigits is None:
27 return_int = True
28 ndigits = 0
29 if hasattr(number, '__round__'):
30 return number.__round__(ndigits)
31
32 if ndigits < 0:
33 raise NotImplementedError('negative ndigits not supported yet')
34 exponent = Decimal('10') ** (-ndigits)
35
36 if PYPY:
37 # Work around issue #24: round() breaks on PyPy with NumPy's types
38 if 'numpy' in repr(type(number)):
39 number = float(number)
40
41 if isinstance(number, Decimal):
42 d = number
43 else:
44 if not PY26:
45 d = Decimal.from_float(number).quantize(exponent,
46 rounding=ROUND_HALF_EVEN)
47 else:
48 d = from_float_26(number).quantize(exponent, rounding=ROUND_HALF_EVEN)
49
50 if return_int:
51 return int(d)
52 else:
53 return float(d)
54
55
56 ### From Python 2.7's decimal.py. Only needed to support Py2.6:
57
58 def from_float_26(f):
59 """Converts a float to a decimal number, exactly.
60
61 Note that Decimal.from_float(0.1) is not the same as Decimal('0.1').
62 Since 0.1 is not exactly representable in binary floating point, the
63 value is stored as the nearest representable value which is
64 0x1.999999999999ap-4. The exact equivalent of the value in decimal
65 is 0.1000000000000000055511151231257827021181583404541015625.
66
67 >>> Decimal.from_float(0.1)
68 Decimal('0.1000000000000000055511151231257827021181583404541015625')
69 >>> Decimal.from_float(float('nan'))
70 Decimal('NaN')
71 >>> Decimal.from_float(float('inf'))
72 Decimal('Infinity')
73 >>> Decimal.from_float(-float('inf'))
74 Decimal('-Infinity')
75 >>> Decimal.from_float(-0.0)
76 Decimal('-0')
77
78 """
79 import math as _math
80 from decimal import _dec_from_triple # only available on Py2.6 and Py2.7 (not 3.3)
81
82 if isinstance(f, (int, long)): # handle integer inputs
83 return Decimal(f)
84 if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float
85 return Decimal(repr(f))
86 if _math.copysign(1.0, f) == 1.0:
87 sign = 0
88 else:
89 sign = 1
90 n, d = abs(f).as_integer_ratio()
91 # int.bit_length() method doesn't exist on Py2.6:
92 def bit_length(d):
93 if d != 0:
94 return len(bin(abs(d))) - 2
95 else:
96 return 0
97 k = bit_length(d) - 1
98 result = _dec_from_triple(sign, str(n*5**k), -k)
99 return result
100
101
102 __all__ = ['newround']