gh-157742: Speed up int multiplication by not zeroing the whole result in x_mul() - #157743
Open
eendebakpt wants to merge 4 commits into
Open
eendebakpt wants to merge 4 commits into
eendebakpt wants to merge 4 commits into
Conversation
x_mul() memset()s the entire product to zero before the gradeschool loop runs, but the i == 0 pass stores z[0:size_b+1] outright rather than accumulating into it, and every later pass only reads digits that the previous pass has already written. Only the top size_a digits -- the carry positions -- actually have to start out zeroed. k_mul() arranges for size_a <= size_b before calling x_mul(), so this replaces a memset of size_a + size_b digits with one of size_a digits. The win is largest exactly where the old code wasted the most: for a single-digit multiplier the zeroing pass was as long as the entire multiplication. Peeling the i == 0 pass out of the loop also drops the redundant load of *pz from the carry dependency chain. The a == b squaring path is unchanged and keeps the full memset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each schoolbook pass stores its final carry into z[i+size_b], a digit no earlier pass has touched, so it can be a plain store rather than an addition onto a pre-zeroed digit. With that, no digit of the result needs zeroing at all. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
x_mul()(schoolbook multiplication inObjects/longobject.c) starts bymemset-ing all digits of the result to zero, then accumulates row by row withcarry += *pz + *pb++ * f.The zeroing is not needed for the non-squaring path. Row 0 can store its
size_b + 1digits outright, and rowionly reads digits that rowi - 1already wrote; each carry slotz[i + size_b]is written exactly once before it is ever read. So no digit needs to start out zero, and the per-rowif (carry) *pz += carrybecomes a plain store.This matters most for the common big × small case (
size_a == 1). Karatsuba and lopsided multiplication callx_mul()for their base cases, so they gain a little too.Benchmarks
pidigitsBenchmark script