Reimplement carrying_add
and borrowing_sub
for signed integers. by Stovent · Pull Request #93873 · rust-lang/rust (original) (raw)
I have been a little busy these past weeks, sorry for late answer.
First, I made the following example that uses both the signed and unsigned versions of the carrying / borrowing methods.
#![feature(bigint_helper_methods)] #![feature(array_zip)]
#[derive(Clone, Copy)] struct SignedBigInt { pub lows: [u8; N], pub high: i8, }
impl SignedBigInt {
/// Subtracts rhs
from self
and returns true if signed overflow occurs, false otherwise.
pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let mut borrow = false;
let lows = self.lows.zip(rhs.lows).map(|(left, right)| {
let (res, b) = left.borrowing_sub(right, borrow);
borrow = b;
res
});
let (high, b) = self.high.borrowing_sub(rhs.high, borrow);
(Self { lows, high }, b)
}
}
fn main() { let left = SignedBigInt { // -32_768 lows: [0], high: -128, }; let right = SignedBigInt { // 127 lows: [127], high: 0, }; let (res, borrow) = left.overflowing_sub(right); // -32_895 overflow to 32_641
assert_eq!(res.high, 0x7F);
assert_eq!(res.lows[0], 0x81);
assert_eq!(borrow, true);
}
From my experience, the signed methods are only useful for fixed-size big integers, since dynamically-sized big ints operations do not have overflow as we simply allocate the size needed for the result. If you need further examples, please tell me which points I missed in those I sent.
Second, regarding a potential name change. It is true that the signed methods are often used differently than the unsigned ones. However, since their behaviour is similar, just using signed semantics instead of unsigned ones, I am not sure whether a name change is really justified. If you still want to rename these methods, I personally cannot think of better names than the existing ones, but I am open for suggestions.