We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contactedHave a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Expand Up | @@ -238,6 +238,7 @@ def limit_denominator(self, max_denominator=1000000): | |
|
|
||
| p0, q0, p1, q1 = 0, 1, 1, 0 | ||
| n, d = self._numerator, self._denominator | ||
| n_original, d_original = n, d | ||
| while True: | ||
| a = n//d | ||
| q2 = q0+a*q1 | ||
| Expand All | @@ -247,12 +248,23 @@ def limit_denominator(self, max_denominator=1000000): | |
| n, d = d, n-a*d | ||
|
|
||
| k = (max_denominator-q0)//q1 | ||
| bound1 = Fraction(p0+k*p1, q0+k*q1) | ||
| bound2 = Fraction(p1, q1) | ||
| if abs(bound2 - self) <= abs(bound1-self): | ||
| return bound2 | ||
| bound1_n = p0 + k*p1 | ||
| bound1_d = q0 + k*q1 | ||
| bound2_n = p1 | ||
| bound2_d = q1 | ||
|
|
||
| # diff1_n = numerator of (bound1 minus self) as a Fraction; | ||
| # etc. for diff1_d, diff2_n, diff2_d | ||
| diff1_n = abs(bound1_n*d_original - n_original*bound1_d) | ||
| diff1_d = d_original * bound1_d | ||
| diff2_n = abs(bound2_n*d_original - n_original*bound2_d) | ||
| diff2_d = d_original * bound2_d | ||
|
|
||
| if diff1_n * diff2_d >= diff2_n * diff1_d: | ||
| # bound2 is closer (or equal) to original as bound 1 | ||
| return Fraction(bound2_n, bound2_d, _normalize=False) | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide commentI just realised that I'm not 100% convinced that the result here is always normalised. There are two parts to being normalised: the numerator must be relatively prime to the denominator, and the denominator must be positive. I'd thought about the first part (which is fine), but not about the second. Is it clear that bound2_d and bound1_d are positive at this point?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide commentAnswer: yes, it's true that bound2_d and bound1_d are positive at this point, though perhaps not 100% clear. In the Euclidean loop above, on the very first iteration a can be negative, but on all subsequent iterations a is nonnegative. And on the first iteration q1 = 0, so that potentially negative a does no harm, and q0 and q1 are guaranteed nonnegative at all times. Then it's easy to check that they must in fact be positive at the point where the loop exits.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide commentThat was my reading of the loop as well, but I didn't write the code (nor name the variables) so I didn't want to change this without another set of eyes; thanks!
Sorry, something went wrong.
All reactions
|
||
| else: | ||
| return bound1 | ||
| return Fraction(bound1_n, bound1_d, _normalize=False) | ||
|
|
||
| @property | ||
| def numerator(a): | ||
| Expand Down | ||
| @@ -0,0 +1,2 @@ | ||
| :meth:`fractions.Fraction.limit_denominator()` performance enhancements. | ||
| Patch by Michael Scott Asato Cuthbert. |
Uh oh!
There was an error while loading. Please reload this page.