@@ -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 ** (<object> 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 (<unsigned long long>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(<Py_ssize_t>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 |