-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Tidy up bigint multiplication methods #132195
Conversation
@rustbot author Currently drafted since tests are failing and I need to fix them, but I wanted to at least save the stuff I typed up for the description. |
This comment has been minimized.
This comment has been minimized.
Let me know when it's ready and I'll take a look. Unless you'd like feedback beforehand, of course. |
☔ The latest upstream changes (presumably #132191) made this pull request unmergeable. Please resolve the merge conflicts. |
83ea534
to
070591e
Compare
Feel free to review the parts of the code that do work, and the API specifically as mentioned in the description. I just know that my naïve implementation for |
This comment has been minimized.
This comment has been minimized.
070591e
to
218de99
Compare
This comment has been minimized.
This comment has been minimized.
218de99
to
0f11119
Compare
This comment has been minimized.
This comment has been minimized.
0f11119
to
35e3b3c
Compare
This comment has been minimized.
This comment has been minimized.
35e3b3c
to
8960e06
Compare
Oh cool, finally got it to work. Glad I added some tests with @rustbot review |
8960e06
to
1a90982
Compare
($left:expr, $right:expr$(, $($arg:tt)+)?) => { | ||
{ | ||
fn runtime() { | ||
assert_eq!($left, $right, $($arg)*); | ||
assert_eq!($left, $right, $($($arg)*),*); |
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.
This was just wrong before but unused, so, it never triggered any errors.
($left:expr, $right:expr) => { | ||
assert_eq_const_safe!($left, $right, concat!(stringify!($left), " == ", stringify!($right))); | ||
}; |
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.
This helped with debugging, so, I kept it.
☔ The latest upstream changes (presumably #132238) made this pull request unmergeable. Please resolve the merge conflicts. |
1a90982
to
5b825d2
Compare
☔ The latest upstream changes (presumably #132458) made this pull request unmergeable. Please resolve the merge conflicts. |
My PR added an intrinsic for a*b+c+d, but didn't expose it, so taking this for that part would be good, and I didn't do anything for signed numbers either. So using this PR for that stuff sounds at least plausible. |
@rustbot author |
7020977
to
d85387f
Compare
@rustbot ready I think I've updated everything, including the PR description, after the other PR which added an intrinsic for this. Hopefully everything looks good now. |
This comment has been minimized.
This comment has been minimized.
d85387f
to
f228458
Compare
You might want to fix up the OP a bit -- it still says "Eventually, an intrinsic will be added to make these more efficient" and " |
/// additional amount of overflow. This allows for chaining together multiple | ||
/// multiplications to create "big integers" which represent larger values. | ||
/// | ||
/// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead. |
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.
suggestion: would be good to also mention carrying_mul_add
here, probably.
Actually, all the code looks good here, so @bors r+ (I would slightly prefer the methods not to be moved around for a simpler diff in uint_macros, but meh.) |
☀️ Test successful - checks-actions |
Finished benchmarking commit (d117b7f): comparison URL. Overall result: ❌✅ regressions and improvements - no action needed@rustbot label: -perf-regression Instruction countThis is the most reliable metric that we have; it was used to determine the overall result at the top of this comment. However, even this metric can sometimes exhibit noise.
Max RSS (memory usage)Results (primary -1.2%, secondary -1.0%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResults (primary -3.6%, secondary -0.8%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 762.584s -> 762.425s (-0.02%) |
This tidies up the library version of the bigint multiplication methods after the addition of the intrinsics in #133663. It follows this summary of what's desired for these methods.
Note that, if
2H = N
, thenuH::MAX * uH::MAX + uH::MAX + uH::MAX
isuN::MAX
, and that we can effectively add two "carry" values without overflowing.For ease of terminology, the "low-order" or "least significant" or "wrapping" half of multiplication will be called the low part, and the "high-order" or "most significant" or "overflowing" half of multiplication will be called the high part. In all cases, the return convention is
(low, high)
and left unchanged by this PR, to be litigated later.API Changes
The original API:
The added API:
Additionally, a naive implementation has been added for
u128
andi128
since there are no double-wide types for those. Eventually, an intrinsic will be added to make these more efficient, but rather than doing this all at once, the library changes are added first.Justifications for API
The unsigned parts are done to ensure consistency with overflowing addition: for a two's complement integer, you want to have unsigned overflow semantics for all parts of the integer except the highest one. This is because overflow for unsigned integers happens on the highest bit (from
MAX
to zero), whereas overflow for signed integers happens on the second highest bit (fromMAX
toMIN
). Since the sign information only matters in the highest part, we use unsigned overflow for everything but that part.There is still discussion on the merits of signed bigint addition methods, since getting the behaviour right is very subtle, but at least for signed bigint multiplication, the sign of the operands does make a difference. So, it feels appropriate that at least until we've nailed down the final API, there should be an option to do signed versions of these methods.
Additionally, while it's unclear whether we need all three versions of bigint multiplication (widening, carrying-1, and carrying-2), since it's possible to have up to two carries without overflow, there should at least be a method to allow that. We could potentially only offer the carry-2 method and expect that adding zero carries afterword will optimise correctly, but again, this can be litigated before stabilisation.
Note on documentation
While a lot of care was put into the documentation for the
widening_mul
andcarrying_mul
methods on unsigned integers, I have not taken this same care forcarrying_mul_add
or the signed versions. While I have updated the doc tests to be more appropriate, there will likely be many documentation changes done before stabilisation.Note on tests
Alongside this change, I've added several tests to ensure that these methods work as expected. These are alongside the codegen tests for the intrinsics.