From 28e836f6a17f96d381dc7dbe99e4e4f19af85d9d Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Tue, 24 Apr 2018 09:31:28 -0800 Subject: [PATCH 1/5] carrying_mul --- text/0000-carrying-mul.md | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 text/0000-carrying-mul.md diff --git a/text/0000-carrying-mul.md b/text/0000-carrying-mul.md new file mode 100644 index 00000000000..9ea92a52655 --- /dev/null +++ b/text/0000-carrying-mul.md @@ -0,0 +1,64 @@ +- Feature Name: carrying_mul +- Start Date: 2018-04-24 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +Add an inherent method to integral types which does a double-wide multiplication. + +# Motivation +[motivation]: #motivation + +Double-wide multiplication is a prerequisite of arbitrary-precision multiplication. Many machine architectures specify an instruction for this operation, and it is cumbersome to otherwise define. It is also a prerequisite to completely define a `u2size` type of double the size of a machine word which, in the author's experience, is useful at times (e.g. modular arithmetic on offsets into large cyclic arrays of unusual length, smoothsort). + +For an integral type of known width, other than the widest (now `u128`), one can define the operation in terms of a wider type, but `usize` has unknown width, and Rust may want to support 128-bit architectures (e.g. RV128) in future. + +As the author writes, the "num-bigint" crate merely uses `u32` as its word type to avoid this difficulty, which is likely suboptimal on 64-bit architectures. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +`pub fn carrying_mul(self, other: Self) -> (Self, Self)` + +Returns the low and high words of the product of `self` and `other`. + +One can, for example, define +Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: + +- Introducing new named concepts. +- Explaining the feature largely in terms of examples. +- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. +- If applicable, provide sample error messages, deprecation warnings, or migration guidance. +- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. + +For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +`pub fn carrying_mul(self, other: Self) -> (Self, Self)` + +Returns the low and high words of the product of `self` and `other`. + +# Drawbacks +[drawbacks]: #drawbacks + +None known + +# Rationale and alternatives +[alternatives]: #alternatives + +The alternative is to not define this method, which means to do a double-wide multiplication, the user must use inline asm (unstable) or do an awkward dance of shifts and multiplications. + +# Prior art +[prior-art]: #prior-art + +This feature is already in many assembly languages (e.g. "mul" on x86, "mulh" on RISC-V M). + +# Unresolved questions +[unresolved]: #unresolved-questions + +- What should we call the method? +- What should the order of return values be? From 74d0010081c05d76e26a3e4cd9acfdce493e72a1 Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Tue, 24 Apr 2018 09:31:46 -0800 Subject: [PATCH 2/5] delete duplicate reference-level explanation --- text/0000-carrying-mul.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/text/0000-carrying-mul.md b/text/0000-carrying-mul.md index 9ea92a52655..1ad55a62e6d 100644 --- a/text/0000-carrying-mul.md +++ b/text/0000-carrying-mul.md @@ -20,10 +20,6 @@ As the author writes, the "num-bigint" crate merely uses `u32` as its word type # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -`pub fn carrying_mul(self, other: Self) -> (Self, Self)` - -Returns the low and high words of the product of `self` and `other`. - One can, for example, define Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: From 9870ae99f28b527d794a3fff173709eaf5638620 Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Tue, 24 Apr 2018 09:40:50 -0800 Subject: [PATCH 3/5] actually commit guide-level explanation --- text/0000-carrying-mul.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/text/0000-carrying-mul.md b/text/0000-carrying-mul.md index 1ad55a62e6d..064d318f9ba 100644 --- a/text/0000-carrying-mul.md +++ b/text/0000-carrying-mul.md @@ -20,16 +20,19 @@ As the author writes, the "num-bigint" crate merely uses `u32` as its word type # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -One can, for example, define -Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: - -- Introducing new named concepts. -- Explaining the feature largely in terms of examples. -- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. -- If applicable, provide sample error messages, deprecation warnings, or migration guidance. -- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. - -For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. +In general, the product of an m-bit and an n-bit number has (m+n) bits. If one wishes to define arbitrary-precision arithmetic, one (usually) chooses a word size, and defines the multiple-precision operations in terms of primitive operations on this type. The `carrying_mul` function allows one to do so conveniently, for example: + +```rust +pub struct u2size { msw: usize, lsw: usize } + +impl Mul for u2size { + fn mul(self, other: Self) -> Self { + let (lsw, c) = self.lsw.carrying_mul(other.lsw); + u2size { lsw, msw: c + self.msw * other.lsw + + self.lsw * other.msw } + } +} +``` # Reference-level explanation [reference-level-explanation]: #reference-level-explanation From fb029b49b6324178940cb8f97b5c062d2098e154 Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Tue, 24 Apr 2018 10:21:04 -0800 Subject: [PATCH 4/5] note another alternative --- text/0000-carrying-mul.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-carrying-mul.md b/text/0000-carrying-mul.md index 064d318f9ba..5e317dcf855 100644 --- a/text/0000-carrying-mul.md +++ b/text/0000-carrying-mul.md @@ -49,7 +49,8 @@ None known # Rationale and alternatives [alternatives]: #alternatives -The alternative is to not define this method, which means to do a double-wide multiplication, the user must use inline asm (unstable) or do an awkward dance of shifts and multiplications. +- We could not define this method, which means to do a double-wide multiplication, the user must use inline asm (unstable) or do an awkward dance of shifts and multiplications. +- We could define a `mul_high` method which merely returns the high word. # Prior art [prior-art]: #prior-art From 329e58bfce8df4794e5b8914ae4a66cb5076b0b9 Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Wed, 5 Dec 2018 00:09:07 -0800 Subject: [PATCH 5/5] rename as `widening_mul` --- text/{0000-carrying-mul.md => 0000-widening-mul.md} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename text/{0000-carrying-mul.md => 0000-widening-mul.md} (92%) diff --git a/text/0000-carrying-mul.md b/text/0000-widening-mul.md similarity index 92% rename from text/0000-carrying-mul.md rename to text/0000-widening-mul.md index 5e317dcf855..8d2f63bac6a 100644 --- a/text/0000-carrying-mul.md +++ b/text/0000-widening-mul.md @@ -1,4 +1,4 @@ -- Feature Name: carrying_mul +- Feature Name: widening_mul - Start Date: 2018-04-24 - RFC PR: - Rust Issue: @@ -20,14 +20,14 @@ As the author writes, the "num-bigint" crate merely uses `u32` as its word type # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -In general, the product of an m-bit and an n-bit number has (m+n) bits. If one wishes to define arbitrary-precision arithmetic, one (usually) chooses a word size, and defines the multiple-precision operations in terms of primitive operations on this type. The `carrying_mul` function allows one to do so conveniently, for example: +In general, the product of an m-bit and an n-bit number has (m+n) bits. If one wishes to define arbitrary-precision arithmetic, one (usually) chooses a word size, and defines the multiple-precision operations in terms of primitive operations on this type. The `widening_mul` function allows one to do so conveniently, for example: ```rust pub struct u2size { msw: usize, lsw: usize } impl Mul for u2size { fn mul(self, other: Self) -> Self { - let (lsw, c) = self.lsw.carrying_mul(other.lsw); + let (lsw, c) = self.lsw.widening_mul(other.lsw); u2size { lsw, msw: c + self.msw * other.lsw + self.lsw * other.msw } } @@ -37,7 +37,7 @@ impl Mul for u2size { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -`pub fn carrying_mul(self, other: Self) -> (Self, Self)` +`pub fn widening_mul(self, other: Self) -> (Self, Self)` Returns the low and high words of the product of `self` and `other`.