Skip to content

Commit 223bbc3

Browse files
committed
Minor restructuring of BigInt::set_bit
1 parent 30ec1f8 commit 223bbc3

File tree

1 file changed

+56
-65
lines changed

1 file changed

+56
-65
lines changed

src/bigint.rs

Lines changed: 56 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3306,75 +3306,66 @@ impl BigInt {
33063306
// |-- bit at position 'trailing_zeros'
33073307
// where !x is obtained from x by flipping each bit
33083308
let trailing_zeros = self.data.trailing_zeros().unwrap();
3309-
match Ord::cmp(&bit, &trailing_zeros) {
3310-
Less => {
3311-
if value {
3312-
// We need to flip each bit from position 'bit' to 'trailing_zeros', both inclusive
3313-
// ... 1 !x 1 0 ... 0 ... 0
3314-
// |-- bit at position 'bit'
3315-
// |-- bit at position 'trailing_zeros'
3316-
// bit_mask: 1 1 ... 1 0 .. 0
3317-
// We do this by xor'ing with the bit_mask
3318-
let index_lo = (bit / bits_per_digit).to_usize().unwrap();
3319-
let index_hi =
3320-
(trailing_zeros / bits_per_digit).to_usize().unwrap();
3321-
let bit_mask_lo = BigDigit::MAX << (bit % bits_per_digit);
3322-
let bit_mask_hi = BigDigit::MAX
3323-
>> (bits_per_digit - 1 - (trailing_zeros % bits_per_digit));
3324-
let digits = self.digits_mut();
3325-
3326-
if index_lo == index_hi {
3327-
digits[index_lo] ^= bit_mask_lo & bit_mask_hi;
3328-
} else {
3329-
digits[index_lo] ^= bit_mask_lo;
3330-
for index in (index_lo + 1)..index_hi {
3331-
digits[index] = BigDigit::MAX;
3332-
}
3333-
digits[index_hi] ^= bit_mask_hi;
3334-
}
3335-
} else {
3336-
// Bit is already cleared
3309+
if bit > trailing_zeros {
3310+
self.data.set_bit(bit, !value);
3311+
} else if bit == trailing_zeros && !value {
3312+
// Clearing the bit at position `trailing_zeros` is dealt with by doing
3313+
// similarly to what `bitand_neg_pos` does, except we start at digit
3314+
// `bit_index`. All digits below `bit_index` are guaranteed to be zero,
3315+
// so initially we have `carry_in` = `carry_out` = 1.
3316+
let bit_index = (bit / bits_per_digit).to_usize().unwrap();
3317+
let bit_mask = (1 as BigDigit) << (bit % bits_per_digit);
3318+
let mut digit_iter = self.digits_mut().iter_mut().skip(bit_index);
3319+
let mut carry_in = 1;
3320+
let mut carry_out = 1;
3321+
3322+
let digit = digit_iter.next().unwrap();
3323+
let twos_in = negate_carry(*digit, &mut carry_in);
3324+
let twos_out = twos_in & !bit_mask;
3325+
*digit = negate_carry(twos_out, &mut carry_out);
3326+
3327+
for digit in digit_iter {
3328+
if carry_in == 0 && carry_out == 0 {
3329+
// Exit the loop since no more digits can change
3330+
break;
33373331
}
3332+
let twos = negate_carry(*digit, &mut carry_in);
3333+
*digit = negate_carry(twos, &mut carry_out);
33383334
}
3339-
Equal => {
3340-
if value {
3341-
// Bit is already set
3342-
} else {
3343-
// Clearing the bit at position `trailing_zeros` is the only non-trivial
3344-
// case and is dealt with by doing similarly to what `bitand_neg_pos`
3345-
// does, except we start at digit `bit_index`; all digits below `bit_index`
3346-
// are guaranteed to be zero, so initially we must have
3347-
// `carry_in` = `carry_out` = 1
3348-
let bit_index = (bit / bits_per_digit).to_usize().unwrap();
3349-
let bit_mask = (1 as BigDigit) << (bit % bits_per_digit);
3350-
let mut digit_iter = self.digits_mut().iter_mut().skip(bit_index);
3351-
let mut carry_in = 1;
3352-
let mut carry_out = 1;
3353-
3354-
let digit = digit_iter.next().unwrap();
3355-
let twos_in = negate_carry(*digit, &mut carry_in);
3356-
let twos_out = twos_in & !bit_mask;
3357-
*digit = negate_carry(twos_out, &mut carry_out);
3358-
3359-
for digit in digit_iter {
3360-
if carry_in == 0 && carry_out == 0 {
3361-
// Exit the loop since no more digits can change
3362-
break;
3363-
}
3364-
let twos = negate_carry(*digit, &mut carry_in);
3365-
*digit = negate_carry(twos, &mut carry_out);
3366-
}
3367-
3368-
if carry_out != 0 {
3369-
// All digits have been traversed and there is a carry
3370-
debug_assert_eq!(carry_in, 0);
3371-
self.digits_mut().push(1);
3372-
}
3373-
}
3335+
3336+
if carry_out != 0 {
3337+
// All digits have been traversed and there is a carry
3338+
debug_assert_eq!(carry_in, 0);
3339+
self.digits_mut().push(1);
33743340
}
3375-
Greater => {
3376-
self.data.set_bit(bit, !value);
3341+
} else if bit < trailing_zeros && value {
3342+
// Flip each bit from position 'bit' to 'trailing_zeros', both inclusive
3343+
// ... 1 !x 1 0 ... 0 ... 0
3344+
// |-- bit at position 'bit'
3345+
// |-- bit at position 'trailing_zeros'
3346+
// bit_mask: 1 1 ... 1 0 .. 0
3347+
// We do this by xor'ing with the bit_mask
3348+
let index_lo = (bit / bits_per_digit).to_usize().unwrap();
3349+
let index_hi =
3350+
(trailing_zeros / bits_per_digit).to_usize().unwrap();
3351+
let bit_mask_lo = big_digit::MAX << (bit % bits_per_digit);
3352+
let bit_mask_hi = big_digit::MAX
3353+
>> (bits_per_digit - 1 - (trailing_zeros % bits_per_digit));
3354+
let digits = self.digits_mut();
3355+
3356+
if index_lo == index_hi {
3357+
digits[index_lo] ^= bit_mask_lo & bit_mask_hi;
3358+
} else {
3359+
digits[index_lo] ^= bit_mask_lo;
3360+
for index in (index_lo + 1)..index_hi {
3361+
digits[index] = big_digit::MAX;
3362+
}
3363+
digits[index_hi] ^= bit_mask_hi;
33773364
}
3365+
} else {
3366+
// We end up here in two cases:
3367+
// * bit == trailing_zeros && value: Bit is already set
3368+
// * bit < trailing_zeros && !value: Bit is already cleared
33783369
}
33793370
}
33803371
}

0 commit comments

Comments
 (0)