Skip to content

Commit cc15047

Browse files
committed
Add carrying_add, borrowing_sub, widening_mul, carrying_mul methods to integers
1 parent ad02dc4 commit cc15047

File tree

4 files changed

+202
-0
lines changed

4 files changed

+202
-0
lines changed

Diff for: library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#![feature(const_alloc_layout)]
7777
#![feature(const_arguments_as_str)]
7878
#![feature(const_assert_type)]
79+
#![feature(const_bigint_helper_methods)]
7980
#![feature(const_caller_location)]
8081
#![feature(const_cell_into_inner)]
8182
#![feature(const_discriminant)]

Diff for: library/core/src/num/int_macros.rs

+54
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,33 @@ macro_rules! int_impl {
13071307
(a as Self, b)
13081308
}
13091309

1310+
/// Calculates `self + rhs + carry` without the ability to overflow.
1311+
///
1312+
/// Performs "ternary addition" which takes in an extra bit to add, and may return an
1313+
/// additional bit of overflow. This allows for chaining together multiple additions
1314+
/// to create "big integers" which represent larger values.
1315+
///
1316+
/// # Examples
1317+
///
1318+
/// Basic usage
1319+
///
1320+
/// ```
1321+
/// #![feature(bigint_helper_methods)]
1322+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
1323+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
1324+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, false));")]
1325+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, false));")]
1326+
/// ```
1327+
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
1328+
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
1329+
#[must_use = "this returns the result of the operation, \
1330+
without modifying the original"]
1331+
#[inline]
1332+
pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
1333+
let (sum, carry) = (self as $UnsignedT).carrying_add(rhs as $UnsignedT, carry);
1334+
(sum as $SelfT, carry)
1335+
}
1336+
13101337
/// Calculates `self` - `rhs`
13111338
///
13121339
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
@@ -1331,6 +1358,33 @@ macro_rules! int_impl {
13311358
(a as Self, b)
13321359
}
13331360

1361+
/// Calculates `self - rhs - borrow` without the ability to overflow.
1362+
///
1363+
/// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return
1364+
/// an additional bit of overflow. This allows for chaining together multiple subtractions
1365+
/// to create "big integers" which represent larger values.
1366+
///
1367+
/// # Examples
1368+
///
1369+
/// Basic usage
1370+
///
1371+
/// ```
1372+
/// #![feature(bigint_helper_methods)]
1373+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
1374+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
1375+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, false));")]
1376+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, false));")]
1377+
/// ```
1378+
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
1379+
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
1380+
#[must_use = "this returns the result of the operation, \
1381+
without modifying the original"]
1382+
#[inline]
1383+
pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
1384+
let (sum, borrow) = (self as $UnsignedT).borrowing_sub(rhs as $UnsignedT, borrow);
1385+
(sum as $SelfT, borrow)
1386+
}
1387+
13341388
/// Calculates the multiplication of `self` and `rhs`.
13351389
///
13361390
/// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow

Diff for: library/core/src/num/mod.rs

+87
Original file line numberDiff line numberDiff line change
@@ -89,27 +89,104 @@ depending on the target pointer size.
8989
};
9090
}
9191

92+
macro_rules! widening_impl {
93+
($SelfT:ty, $WideT:ty, $BITS:literal) => {
94+
/// Calculates the complete product `self * rhs` without the possibility to overflow.
95+
///
96+
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
97+
/// of the result as two separate values, in that order.
98+
///
99+
/// # Examples
100+
///
101+
/// Basic usage:
102+
///
103+
/// Please note that this example is shared between integer types.
104+
/// Which explains why `u32` is used here.
105+
///
106+
/// ```
107+
/// #![feature(bigint_helper_methods)]
108+
/// assert_eq!(5u32.widening_mul(2), (10, 0));
109+
/// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2));
110+
/// ```
111+
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
112+
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
113+
#[must_use = "this returns the result of the operation, \
114+
without modifying the original"]
115+
#[inline]
116+
pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
117+
// note: longer-term this should be done via an intrinsic,
118+
// but for now we can deal without an impl for u128/i128
119+
// SAFETY: overflow will be contained within the wider types
120+
let wide = unsafe { (self as $WideT).unchecked_mul(rhs as $WideT) };
121+
(wide as $SelfT, (wide >> $BITS) as $SelfT)
122+
}
123+
124+
/// Calculates the "full multiplication" `self * rhs + carry`
125+
/// without the possibility to overflow.
126+
///
127+
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
128+
/// of the result as two separate values, in that order.
129+
///
130+
/// Performs "long multiplication" which takes in an extra amount to add, and may return an
131+
/// additional amount of overflow. This allows for chaining together multiple
132+
/// multiplications to create "big integers" which represent larger values.
133+
///
134+
/// # Examples
135+
///
136+
/// Basic usage:
137+
///
138+
/// Please note that this example is shared between integer types.
139+
/// Which explains why `u32` is used here.
140+
///
141+
/// ```
142+
/// #![feature(bigint_helper_methods)]
143+
/// assert_eq!(5u32.carrying_mul(2, 0), (10, 0));
144+
/// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
145+
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
146+
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
147+
/// ```
148+
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
149+
#[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
150+
#[must_use = "this returns the result of the operation, \
151+
without modifying the original"]
152+
#[inline]
153+
pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
154+
// note: longer-term this should be done via an intrinsic,
155+
// but for now we can deal without an impl for u128/i128
156+
// SAFETY: overflow will be contained within the wider types
157+
let wide = unsafe {
158+
(self as $WideT).unchecked_mul(rhs as $WideT).unchecked_add(carry as $WideT)
159+
};
160+
(wide as $SelfT, (wide >> $BITS) as $SelfT)
161+
}
162+
};
163+
}
164+
92165
#[lang = "i8"]
93166
impl i8 {
167+
widening_impl! { i8, i16, 8 }
94168
int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
95169
"[0x12]", "[0x12]", "", "" }
96170
}
97171

98172
#[lang = "i16"]
99173
impl i16 {
174+
widening_impl! { i16, i32, 16 }
100175
int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
101176
"0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
102177
}
103178

104179
#[lang = "i32"]
105180
impl i32 {
181+
widening_impl! { i32, i64, 32 }
106182
int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
107183
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
108184
"[0x12, 0x34, 0x56, 0x78]", "", "" }
109185
}
110186

111187
#[lang = "i64"]
112188
impl i64 {
189+
widening_impl! { i64, i128, 64 }
113190
int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12,
114191
"0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
115192
"0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
@@ -131,6 +208,7 @@ impl i128 {
131208
#[cfg(target_pointer_width = "16")]
132209
#[lang = "isize"]
133210
impl isize {
211+
widening_impl! { isize, i32, 16 }
134212
int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
135213
"0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
136214
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -139,6 +217,7 @@ impl isize {
139217
#[cfg(target_pointer_width = "32")]
140218
#[lang = "isize"]
141219
impl isize {
220+
widening_impl! { isize, i64, 32 }
142221
int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
143222
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
144223
"[0x12, 0x34, 0x56, 0x78]",
@@ -148,6 +227,7 @@ impl isize {
148227
#[cfg(target_pointer_width = "64")]
149228
#[lang = "isize"]
150229
impl isize {
230+
widening_impl! { isize, i128, 64 }
151231
int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807,
152232
12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
153233
"0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
@@ -160,6 +240,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
160240

161241
#[lang = "u8"]
162242
impl u8 {
243+
widening_impl! { u8, u16, 8 }
163244
uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
164245
"[0x12]", "", "" }
165246

@@ -693,18 +774,21 @@ impl u8 {
693774

694775
#[lang = "u16"]
695776
impl u16 {
777+
widening_impl! { u16, u32, 16 }
696778
uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
697779
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
698780
}
699781

700782
#[lang = "u32"]
701783
impl u32 {
784+
widening_impl! { u32, u64, 32 }
702785
uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
703786
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
704787
}
705788

706789
#[lang = "u64"]
707790
impl u64 {
791+
widening_impl! { u64, u128, 64 }
708792
uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
709793
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
710794
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
@@ -727,13 +811,15 @@ impl u128 {
727811
#[cfg(target_pointer_width = "16")]
728812
#[lang = "usize"]
729813
impl usize {
814+
widening_impl! { usize, u32, 16 }
730815
uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
731816
"[0x34, 0x12]", "[0x12, 0x34]",
732817
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
733818
}
734819
#[cfg(target_pointer_width = "32")]
735820
#[lang = "usize"]
736821
impl usize {
822+
widening_impl! { usize, u64, 32 }
737823
uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
738824
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
739825
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -742,6 +828,7 @@ impl usize {
742828
#[cfg(target_pointer_width = "64")]
743829
#[lang = "usize"]
744830
impl usize {
831+
widening_impl! { usize, u128, 64 }
745832
uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
746833
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
747834
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",

Diff for: library/core/src/num/uint_macros.rs

+60
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,36 @@ macro_rules! uint_impl {
13781378
(a as Self, b)
13791379
}
13801380

1381+
/// Calculates `self + rhs + carry` without the ability to overflow.
1382+
///
1383+
/// Performs "ternary addition" which takes in an extra bit to add, and may return an
1384+
/// additional bit of overflow. This allows for chaining together multiple additions
1385+
/// to create "big integers" which represent larger values.
1386+
///
1387+
/// # Examples
1388+
///
1389+
/// Basic usage
1390+
///
1391+
/// ```
1392+
/// #![feature(bigint_helper_methods)]
1393+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
1394+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
1395+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
1396+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
1397+
/// ```
1398+
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
1399+
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
1400+
#[must_use = "this returns the result of the operation, \
1401+
without modifying the original"]
1402+
#[inline]
1403+
pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
1404+
// note: longer-term this should be done via an intrinsic, but this has been shown
1405+
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
1406+
let (a, b) = self.overflowing_add(rhs);
1407+
let (c, d) = a.overflowing_add(carry as $SelfT);
1408+
(c, b | d)
1409+
}
1410+
13811411
/// Calculates `self` - `rhs`
13821412
///
13831413
/// Returns a tuple of the subtraction along with a boolean indicating
@@ -1403,6 +1433,36 @@ macro_rules! uint_impl {
14031433
(a as Self, b)
14041434
}
14051435

1436+
/// Calculates `self - rhs - borrow` without the ability to overflow.
1437+
///
1438+
/// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return
1439+
/// an additional bit of overflow. This allows for chaining together multiple subtractions
1440+
/// to create "big integers" which represent larger values.
1441+
///
1442+
/// # Examples
1443+
///
1444+
/// Basic usage
1445+
///
1446+
/// ```
1447+
/// #![feature(bigint_helper_methods)]
1448+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
1449+
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
1450+
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, true));")]
1451+
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
1452+
/// ```
1453+
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
1454+
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
1455+
#[must_use = "this returns the result of the operation, \
1456+
without modifying the original"]
1457+
#[inline]
1458+
pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
1459+
// note: longer-term this should be done via an intrinsic, but this has been shown
1460+
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
1461+
let (a, b) = self.overflowing_sub(rhs);
1462+
let (c, d) = a.overflowing_sub(borrow as $SelfT);
1463+
(c, b | d)
1464+
}
1465+
14061466
/// Calculates the multiplication of `self` and `rhs`.
14071467
///
14081468
/// Returns a tuple of the multiplication along with a boolean

0 commit comments

Comments
 (0)