New issue
Have 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
bpo-43420: Simple optimizations for Fraction's arithmetics #24779
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
598b3c9
Merge Fraction._add/sub() to a common helper _add_sub_()
skirpichev 430e476
bpo-43420: Simple optimizations for Fraction's arithmetics
skirpichev 046c84e
Use Fraction's private attributes in arithmetic methods
skirpichev 772bec6
Rational addition/substraction: special-case g2 == 1
skirpichev 3d5d321
Special-case for trivial gcd in Fraction._mul()/_div() as well
skirpichev 32778ab
Amend _add_sub_() comment for fractions, obtained from floats
skirpichev ea38398
Revert "Use Fraction's private attributes in arithmetic methods"
skirpichev f4b151a
Revert 598b3c9630 & make _add()/_sub() less nested
skirpichev 40401af
Apply spelling fixes
skirpichev 020037a
Restore back initial d test in _div() per Mark suggestion
skirpichev bde52d1
Add coverage tests (missing in test_fractions.py)
skirpichev 51b52b6
Merge branch 'master' into opt-fractions
skirpichev 2789350
Update Misc/ACKS
skirpichev File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
Misc/NEWS.d/next/Library/2021-03-07-08-03-31.bpo-43420.cee_X5.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Improve performance of class:`fractions.Fraction` arithmetics for large | ||
components. Contributed by Sergey B. Kirpichev. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the "> 1" tests should be removed. The cost of a test is in the same ballpark as the cost of a division. The code is clearer if you just always divide. The performance gain mostly comes from two small gcd's being faster than a single big gcd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, I didn't benchmark this closely, but...
This is a micro-optimization, yes. But ">" has not same cost as "//" even in the CPython:
Maybe my measurements are primitive, but there is some pattern...
I tried to explain reasons for branching in the comment above code. Careful reader might ask: why you don't include same optimizations in the
_mul
as in_add/sub
?On another hand, gmplib doesn't use thise optimizations (c.f. same in mpz_add/sub). SymPy's PythonRational class - too.
So, I did my best in defending those branches and I'm fine with removing, if @tim-one has no arguments against.
This is more important, yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? Comparing
g
to 1 takes, at worst, small constant time, independent of how many digitsg
has. Butn // 1
takes time proportional to the number of internal digits inn
- it's a slow, indirect way of making a physical copy ofn
. Since we expectg
to be 1 most of the time, and these are unbounded ints, the case for checkingg > 1
seems clear to me.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind either way.
If it were just me, I would leave out the '> 1' tests because:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That just doesn't make much sense to me. On my box just now, with the released 3.9.1:
So doing the useless division not only drove the per-iteration measure from 24.2 to 32.4, the unit increased by a factor of 1000(!), from nanoseconds to microseconds. That's using, by construction, an exactly 100,001 bit numerator.
And, no, removing the test barely improves that relative disaster at all:
BTW, as expected, boost the number of numerator bits by a factor of 10 (to a million+1), and per-loop expense also becomes 10 times as much; cut it by a factor 10, and similarly the per-loop expense is also cut by a factor of 10.
With respect to the BPO message you linked to, it appeared atypical: both gcds were greater than 1:
(10 / 3) * (6 / 5)
, so there was never any possibility of testing for> 1
paying off (while in real life a gcd of 1 is probably most common, and when multiplying Fractions obtained from floats gcd=1 is certain unless one of the inputs is an even integer (edited: used to say 0, but it's broader than just that)).