@@ -50,6 +50,11 @@ import sys
5050
5151cdef bint _decimal_supports_integer_ratio = hasattr (Decimal, " as_integer_ratio" ) # Py3.6+
5252cdef object _operator_index = operator.index
53+ cdef object math_gcd
54+ try :
55+ math_gcd = math.gcd
56+ except AttributeError :
57+ pass
5358
5459
5560# Cache widely used 10**x int objects.
@@ -89,25 +94,24 @@ cdef pow10(long long i):
8994
9095cdef extern from * :
9196 """
92- #if PY_VERSION_HEX < 0x030500F0 || !CYTHON_COMPILING_IN_CPYTHON
97+ #if PY_VERSION_HEX < 0x030500F0 || PY_VERSION_HEX >= 0x030d0000 || !CYTHON_COMPILING_IN_CPYTHON
9398 #define _PyLong_GCD(a, b) (NULL)
9499 #endif
95100 """
96- # CPython 3.5+ has a fast PyLong GCD implementation that we can use.
101+ # CPython 3.5-3.12 has a fast PyLong GCD implementation that we can use.
102+ # In CPython 3.13, math.gcd() is fast enough to call it directly.
97103 int PY_VERSION_HEX
98- int IS_CPYTHON " CYTHON_COMPILING_IN_CPYTHON"
104+ int HAS_PYLONG_GCD " ( CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000) "
99105 _PyLong_GCD(a, b)
100106
101107
102108cpdef _gcd(a, b):
103109 """ Calculate the Greatest Common Divisor of a and b as a non-negative number.
104110 """
105- if PY_VERSION_HEX < 0x030500F0 or not IS_CPYTHON:
111+ if PY_VERSION_HEX >= 0x030d0000 :
112+ return math_gcd(a, b)
113+ if PY_VERSION_HEX < 0x030500F0 or not HAS_PYLONG_GCD:
106114 return _gcd_fallback(a, b)
107- if not isinstance (a, int ):
108- a = int (a)
109- if not isinstance (b, int ):
110- b = int (b)
111115 return _PyLong_GCD(a, b)
112116
113117
@@ -134,38 +138,6 @@ cdef cunumber _igcd(cunumber a, cunumber b):
134138 return a
135139
136140
137- cdef cunumber _ibgcd(cunumber a, cunumber b):
138- """ Binary GCD algorithm.
139- See https://en.wikipedia.org/wiki/Binary_GCD_algorithm
140- """
141- cdef uint shift = 0
142- if not a:
143- return b
144- if not b:
145- return a
146-
147- # Find common pow2 factors.
148- while not (a| b) & 1 :
149- a >>= 1
150- b >>= 1
151- shift += 1
152-
153- # Exclude factor 2.
154- while not a & 1 :
155- a >>= 1
156-
157- # a is always odd from here on.
158- while b:
159- while not b & 1 :
160- b >>= 1
161- if a > b:
162- a, b = b, a
163- b -= a
164-
165- # Restore original pow2 factor.
166- return a << shift
167-
168-
169141cdef _py_gcd(ullong a, ullong b):
170142 if a <= < ullong> INT_MAX and b <= < ullong> INT_MAX:
171143 return < int > _igcd[uint](< uint> a, < uint> b)
@@ -455,6 +427,10 @@ cdef class Fraction:
455427 if denominator == 0 :
456428 raise ZeroDivisionError (f' Fraction({numerator}, 0)' )
457429 if _normalize:
430+ if not isinstance (numerator, int ):
431+ numerator = int (numerator)
432+ if not isinstance (denominator, int ):
433+ denominator = int (denominator)
458434 g = _gcd(numerator, denominator)
459435 # NOTE: 'is' tests on integers are generally a bad idea, but
460436 # they are fast and if they fail here, it'll still be correct
0 commit comments