Skip to content

Commit 420f0df

Browse files
authored
Minor optimization for Fractions.limit_denominator (GH-93730)
When we construct the upper and lower candidates in limit_denominator, the numerator and denominator are already relatively prime (and the denominator positive) by construction, so there's no need to go through the usual normalisation in the constructor. This saves a couple of potentially expensive gcd calls. Suggested by Michael Scott Asato Cuthbert in GH-93477.
1 parent 8305137 commit 420f0df

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

Lib/fractions.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -245,14 +245,16 @@ def limit_denominator(self, max_denominator=1000000):
245245
break
246246
p0, q0, p1, q1 = p1, q1, p0+a*p1, q2
247247
n, d = d, n-a*d
248-
249248
k = (max_denominator-q0)//q1
250-
bound1 = Fraction(p0+k*p1, q0+k*q1)
251-
bound2 = Fraction(p1, q1)
252-
if abs(bound2 - self) <= abs(bound1-self):
253-
return bound2
249+
250+
# Determine which of the candidates (p0+k*p1)/(q0+k*q1) and p1/q1 is
251+
# closer to self. The distance between them is 1/(q1*(q0+k*q1)), while
252+
# the distance from p1/q1 to self is d/(q1*self._denominator). So we
253+
# need to compare 2*(q0+k*q1) with self._denominator/d.
254+
if 2*d*(q0+k*q1) <= self._denominator:
255+
return Fraction(p1, q1, _normalize=False)
254256
else:
255-
return bound1
257+
return Fraction(p0+k*p1, q0+k*q1, _normalize=False)
256258

257259
@property
258260
def numerator(a):

0 commit comments

Comments
 (0)