Avoid repetitive calculations of "10 ** x" for the most common 0 <= x… · scoder/quicktions@c20add5 (original) (raw)
`@@ -43,6 +43,30 @@ import sys
`
43
43
`cdef bint _decimal_supports_integer_ratio = hasattr(Decimal, "as_integer_ratio") # Py3.6+
`
44
44
``
45
45
``
``
46
`+
Cache widely used 10**x int objects.
`
``
47
`+
DEF CACHED_POW10 = 64
`
``
48
+
``
49
`+
cdef tuple _cache_pow10():
`
``
50
`+
cdef int i
`
``
51
`+
l = []
`
``
52
`+
x = 1
`
``
53
`+
for i in range(CACHED_POW10):
`
``
54
`+
l.append(x)
`
``
55
`+
x *= 10
`
``
56
`+
return tuple(l)
`
``
57
+
``
58
`+
cdef tuple POW_10 = _cache_pow10()
`
``
59
+
``
60
+
``
61
`+
cdef pow10(Py_ssize_t i):
`
``
62
`+
if 0 <= i < CACHED_POW10:
`
``
63
`+
return POW_10[i]
`
``
64
`+
else:
`
``
65
`+
return 10 ** ( i)
`
``
66
+
``
67
+
``
68
`+
Half-private GCD implementation.
`
``
69
+
46
70
`cdef unsigned long long _abs(long long x):
`
47
71
`if x == PY_LLONG_MIN:
`
48
72
`return (PY_LLONG_MAX) + 1
`
`@@ -244,6 +268,7 @@ cdef class Fraction:
`
244
268
`@classmethod
`
245
269
`def from_decimal(cls, dec):
`
246
270
`"""Converts a finite Decimal instance to a rational number, exactly."""
`
``
271
`+
cdef Py_ssize_t exp
`
247
272
`if isinstance(dec, numbers.Integral):
`
248
273
` dec = Decimal(int(dec))
`
249
274
`elif not isinstance(dec, Decimal):
`
`@@ -258,9 +283,9 @@ cdef class Fraction:
`
258
283
`if sign:
`
259
284
` digits = -digits
`
260
285
`if exp >= 0:
`
261
``
`-
return cls(digits * 10 ** exp)
`
``
286
`+
return cls(digits * pow10(exp))
`
262
287
`else:
`
263
``
`-
return cls(digits, 10 ** -exp)
`
``
288
`+
return cls(digits, pow10(-exp))
`
264
289
``
265
290
`def limit_denominator(self, max_denominator=1000000):
`
266
291
`"""Closest Fraction to self with denominator at most max_denominator.
`
`@@ -458,7 +483,7 @@ cdef class Fraction:
`
458
483
`return floor
`
459
484
`else:
`
460
485
`return floor + 1
`
461
``
`-
shift = 10**abs(ndigits)
`
``
486
`+
shift = pow10(abs(ndigits))
`
462
487
`# See _operator_fallbacks.forward to check that the results of
`
463
488
`# these operations will always be Fraction and therefore have
`
464
489
`# round().
`
`@@ -822,6 +847,7 @@ cdef _raise_invalid_input(s):
`
822
847
``
823
848
`cdef tuple _parse_fraction(AnyString s):
`
824
849
` cdef size_t i, dec_pos = 0, exp_pos = 0, dec_len = 0
`
``
850
`+
cdef Py_ssize_t shift
`
825
851
` cdef Py_UCS4 c
`
826
852
` cdef AnyString numerator, denominator
`
827
853
``
`@@ -904,8 +930,8 @@ cdef tuple _parse_fraction(AnyString s):
`
904
930
`if neg:
`
905
931
` num = -num
`
906
932
`if shift > 0:
`
907
``
`-
num *= 10 ** shift
`
``
933
`+
num *= pow10(shift)
`
908
934
`elif shift < 0:
`
909
``
`-
denom = 10 ** -shift
`
``
935
`+
denom = pow10(-shift)
`
910
936
``
911
937
`return num, denom
`