Just thinking more about the unsigned/signed problem, at least for addition/subtraction. Going to use the term "word" to mean digit, limb, or whatever unit you have in a bigint, for simplicity.
Basically, the issue is that overflow has a different definition for signed/unsigned integers: for unsigned integers, you overflow from MAX to 0, but for signed, you overflow from MAX to MIN.
For intermediate words, you always want to have the unsigned overflow behaviour: you get a new carry if you overflow past all of your bits. But for the last word, you want to know whether you overflowed in the proper sense, since it determines whether you need to add a new unit. So, it feels apt that rather than just returning bool
here, we should return the value of that new unit directly.
So, what feels like we should be doing:
- have
carrying_add
and carrying_sub
/borrowing_sub
which use the current signature of (T, T, bool) -> (T, bool)
, but always have unsigned semantics
- have
extending_add
and extending_sub
which have the signature (T, T, bool) -> (T, Option<T>)
The extending
operation would have the following implementations for unsigned/signed characters:
fn extending_add_unsigned(lhs: u32, rhs: u32, carry: bool) -> (u32, Option<u32>) {
let (sum, overflow1) = lhs.overflowing_add(rhs);
let (sum, overflow2) = sum.overflowing_add(carry as u32);
(sum, (overflow1 | overflow2).then(1))
}
fn extending_add_signed(lhs: i32, rhs: i32, carry: bool) -> (i32, Option<i32>) {
let (sum, overflow1) = lhs.overflowing_add(rhs);
let (sum, overflow2) = sum.overflowing_add(carry as i32);
(sum, (overflow1 | overflow2).then_some(|| if overflow1 != overflow2 {
-1
} else {
0
}))
}
I'm pretty sure the signed logic is correct, but I'll need to double-check my work later.
Also, based upon the feedback we've gotten from people: while the term "borrow" might be common in American teaching of subtraction, "carry" doesn't have any ambiguity and is how the instructions are generally named, so, I kind of prefer renaming borrowing_sub
to just carrying_sub
for less confusion.