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

`