Skip to content

Commit 152bf65

Browse files
committed
More tests and comments
1 parent 58a8163 commit 152bf65

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

src/bigint.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3259,9 +3259,9 @@ impl BigInt {
32593259
/// uses the two's complement for negative numbers
32603260
pub fn bit(&self, bit: u64) -> bool {
32613261
// Let the binary representation of a number be
3262-
// x 1 0 ... 0
3262+
// ... 0 x 1 0 ... 0
32633263
// Then the two's complement is
3264-
// !x 1 0 ... 0
3264+
// ... 1 !x 1 0 ... 0
32653265
// where !x is obtained from x by flipping each bit
32663266
let b = self.data.bit(bit);
32673267
if self.is_negative() && bit > self.data.trailing_zeros().unwrap() {
@@ -3275,6 +3275,7 @@ impl BigInt {
32753275
match self.sign {
32763276
Sign::Plus => self.data.set_bit(bit, value),
32773277
Sign::NoSign => {
3278+
// clearing a bit for zero is a no-op
32783279
if value {
32793280
self.data.set_bit(bit, true);
32803281
self.sign = Sign::Plus;
@@ -3283,25 +3284,28 @@ impl BigInt {
32833284
Sign::Minus => {
32843285
let bits_per_digit = u64::from(big_digit::BITS);
32853286
if bit < bits_per_digit * self.len() as u64 {
3286-
let digit_index = (bit / bits_per_digit) as usize;
3287+
// This implementation corresponds to what the function `bitand_neg_pos` does when
3288+
// value=false and what `bitor_neg_pos` does when value=true, except there is no
3289+
// need to explicitly iterate over the digits of the right-hand side
3290+
let bit_index = (bit / bits_per_digit) as usize;
32873291
let bit_mask = (1 as BigDigit) << (bit % bits_per_digit);
32883292
let mut carry_in = 1;
32893293
let mut carry_out = 1;
3290-
for (i, d) in self.digits_mut().iter_mut().enumerate() {
3291-
let twos_in = negate_carry(*d, &mut carry_in);
3292-
let twos_out = if i != digit_index {
3293-
// leave as-is
3294+
for (index, digit) in self.digits_mut().iter_mut().enumerate() {
3295+
let twos_in = negate_carry(*digit, &mut carry_in);
3296+
let twos_out = if index != bit_index {
32943297
twos_in
32953298
} else if value {
3296-
// set bit
32973299
twos_in | bit_mask
32983300
} else {
3299-
// clear bit
33003301
twos_in & !bit_mask
33013302
};
3302-
*d = negate_carry(twos_out, &mut carry_out);
3303+
*digit = negate_carry(twos_out, &mut carry_out);
33033304
}
33043305
} else {
3306+
// The bit to set/clear is outside the represented digits, and thus more significant
3307+
// than the most significant bit of the current number. This corresponds to setting
3308+
// the bit to the negated value (no-op for value=true)
33053309
if !value {
33063310
self.data.set_bit(bit, true);
33073311
}

tests/bigint.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,10 +1316,37 @@ fn test_bit() {
13161316
assert!(BigInt::from(12u8).bit(2));
13171317
assert!(BigInt::from(12u8).bit(3));
13181318
assert!(!BigInt::from(12u8).bit(4));
1319+
assert!(!BigInt::from(12u8).bit(200));
13191320
// -12 = (...110100)_2
13201321
assert!(!BigInt::from(-12i8).bit(0));
13211322
assert!(!BigInt::from(-12i8).bit(1));
13221323
assert!(BigInt::from(-12i8).bit(2));
13231324
assert!(!BigInt::from(-12i8).bit(3));
13241325
assert!(BigInt::from(-12i8).bit(4));
1326+
assert!(BigInt::from(-12i8).bit(200));
1327+
}
1328+
1329+
#[test]
1330+
fn test_set_bit() {
1331+
let mut x = BigInt::zero();
1332+
x.set_bit(200, true);
1333+
assert_eq!(x, BigInt::one() << 200);
1334+
x.set_bit(10, true);
1335+
x.set_bit(200, false);
1336+
assert_eq!(x, BigInt::one() << 10);
1337+
x.set_bit(10, false);
1338+
x.set_bit(5, false);
1339+
assert_eq!(x, BigInt::zero());
1340+
1341+
x = BigInt::from(-12i8);
1342+
x.set_bit(200, true);
1343+
assert_eq!(x, BigInt::from(-12i8));
1344+
x.set_bit(200, false);
1345+
assert_eq!(x, BigInt::from_biguint(Minus, BigUint::from(12u8) | (BigUint::one() << 200)));
1346+
x.set_bit(6, false);
1347+
assert_eq!(x, BigInt::from_biguint(Minus, BigUint::from(76u8) | (BigUint::one() << 200)));
1348+
x.set_bit(6, true);
1349+
assert_eq!(x, BigInt::from_biguint(Minus, BigUint::from(12u8) | (BigUint::one() << 200)));
1350+
x.set_bit(200, true);
1351+
assert_eq!(x, BigInt::from(-12i8));
13251352
}

tests/biguint.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,4 +1828,7 @@ fn test_set_bit() {
18281828
x.set_bit(128, false);
18291829
x.set_bit(130, false);
18301830
assert_eq!(x, (BigUint::from(2u8) << 128) | BigUint::from(2u8));
1831+
x.set_bit(129, false);
1832+
x.set_bit(1, false);
1833+
assert_eq!(x, BigUint::zero());
18311834
}

0 commit comments

Comments
 (0)