Skip to content

Commit f7199bd

Browse files
committed
Check special case for set_bit for negative number
1 parent 8b6a1bb commit f7199bd

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

src/bigint.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3285,10 +3285,17 @@ impl BigInt {
32853285
}
32863286
Sign::Minus => {
32873287
let bits_per_digit = u64::from(big_digit::BITS);
3288-
if bit < bits_per_digit * self.len() as u64 {
3289-
// This implementation corresponds to what the function `bitand_neg_pos` does when
3290-
// value=false and what `bitor_neg_pos` does when value=true, except there is no
3291-
// need to explicitly iterate over the digits of the right-hand side
3288+
// The first part of this `if` condition is not necessary but included because
3289+
// computing trailing_zeros can be avoided when the bit to set/clear is outside
3290+
// the represented digits
3291+
if bit >= bits_per_digit * self.len() as u64
3292+
|| bit > self.data.trailing_zeros().unwrap()
3293+
{
3294+
self.data.set_bit(bit, !value);
3295+
} else {
3296+
// This is the general case that basically corresponds to what `bitor_neg_pos`
3297+
// (when setting bit) or `bitand_neg_pos` (when clearing bit) does, except there
3298+
// is no need to explicitly iterate over the digits of the right-hand side
32923299
let bit_index = (bit / bits_per_digit) as usize;
32933300
let bit_mask = (1 as BigDigit) << (bit % bits_per_digit);
32943301
let mut carry_in = 1;
@@ -3304,13 +3311,6 @@ impl BigInt {
33043311
};
33053312
*digit = negate_carry(twos_out, &mut carry_out);
33063313
}
3307-
} else {
3308-
// The bit to set/clear is outside the represented digits, and thus more significant
3309-
// than the most significant bit of the current number. This corresponds to setting
3310-
// the bit to the negated value (no-op for value=true)
3311-
if !value {
3312-
self.data.set_bit(bit, true);
3313-
}
33143314
}
33153315
}
33163316
}

tests/bigint.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,4 +1349,8 @@ fn test_set_bit() {
13491349
assert_eq!(x, BigInt::from_biguint(Minus, BigUint::from(12u8) | (BigUint::one() << 200)));
13501350
x.set_bit(200, true);
13511351
assert_eq!(x, BigInt::from(-12i8));
1352+
1353+
x = BigInt::from_biguint(Minus, BigUint::one() << 200);
1354+
x.set_bit(40, true);
1355+
assert_eq!(x, BigInt::from_biguint(Minus, (BigUint::one() << 200) - (BigUint::one() << 40)));
13521356
}

0 commit comments

Comments
 (0)