@@ -3258,15 +3258,22 @@ impl BigInt {
3258
3258
/// Returns whether the bit in position `bit` is set,
3259
3259
/// using the two's complement for negative numbers
3260
3260
pub fn bit ( & self , bit : u64 ) -> bool {
3261
- // Let the binary representation of a number be
3262
- // ... 0 x 1 0 ... 0
3263
- // Then the two's complement is
3264
- // ... 1 !x 1 0 ... 0
3265
- // where !x is obtained from x by flipping each bit
3266
- if bit >= u64:: from ( big_digit:: BITS ) * self . len ( ) as u64 {
3267
- self . is_negative ( )
3268
- } else if self . is_negative ( ) && bit > self . data . trailing_zeros ( ) . unwrap ( ) {
3269
- !self . data . bit ( bit)
3261
+ if self . is_negative ( ) {
3262
+ // Let the binary representation of a number be
3263
+ // ... 0 x 1 0 ... 0
3264
+ // Then the two's complement is
3265
+ // ... 1 !x 1 0 ... 0
3266
+ // where !x is obtained from x by flipping each bit
3267
+ if bit >= u64:: from ( big_digit:: BITS ) * self . len ( ) as u64 {
3268
+ true
3269
+ } else {
3270
+ let trailing_zeros = self . data . trailing_zeros ( ) . unwrap ( ) ;
3271
+ match bit. cmp ( & trailing_zeros) {
3272
+ Ordering :: Less => false ,
3273
+ Ordering :: Equal => true ,
3274
+ Ordering :: Greater => !self . data . bit ( bit) ,
3275
+ }
3276
+ }
3270
3277
} else {
3271
3278
self . data . bit ( bit)
3272
3279
}
@@ -3278,39 +3285,58 @@ impl BigInt {
3278
3285
match self . sign {
3279
3286
Sign :: Plus => self . data . set_bit ( bit, value) ,
3280
3287
Sign :: NoSign => {
3281
- // clearing a bit for zero is a no-op
3282
3288
if value {
3283
3289
self . data . set_bit ( bit, true ) ;
3284
3290
self . sign = Sign :: Plus ;
3291
+ } else {
3292
+ // clearing a bit for zero is a no-op
3285
3293
}
3286
3294
}
3287
3295
Sign :: Minus => {
3288
3296
let bits_per_digit = u64:: from ( big_digit:: BITS ) ;
3289
- // The first part of this `if` condition is not necessary but included because
3290
- // computing trailing_zeros can be avoided when the bit to set/clear is outside
3291
- // the represented digits
3292
- if bit >= bits_per_digit * self . len ( ) as u64
3293
- || bit > self . data . trailing_zeros ( ) . unwrap ( )
3294
- {
3295
- self . data . set_bit ( bit, !value) ;
3297
+ if bit >= bits_per_digit * self . len ( ) as u64 {
3298
+ if !value {
3299
+ self . data . set_bit ( bit, true ) ;
3300
+ }
3296
3301
} else {
3297
- // This is the general case that basically corresponds to what `bitor_neg_pos`
3298
- // (when setting bit) or `bitand_neg_pos` (when clearing bit) does, except there
3299
- // is no need to explicitly iterate over the digits of the right-hand side
3300
- let bit_index = ( bit / bits_per_digit) . to_usize ( ) . unwrap ( ) ;
3301
- let bit_mask = ( 1 as BigDigit ) << ( bit % bits_per_digit) ;
3302
- let mut carry_in = 1 ;
3303
- let mut carry_out = 1 ;
3304
- for ( index, digit) in self . digits_mut ( ) . iter_mut ( ) . enumerate ( ) {
3302
+ let trailing_zeros = self . data . trailing_zeros ( ) . unwrap ( ) ;
3303
+ if bit > trailing_zeros {
3304
+ self . data . set_bit ( bit, !value) ;
3305
+ } else if bit < trailing_zeros && !value {
3306
+ // bit is already cleared
3307
+ } else if bit == trailing_zeros && value {
3308
+ // bit is already set
3309
+ } else {
3310
+ // general case
3311
+ let bit_index = ( bit / bits_per_digit) . to_usize ( ) . unwrap ( ) ;
3312
+ let bit_mask = ( 1 as BigDigit ) << ( bit % bits_per_digit) ;
3313
+ let mut carry_in = 1 ;
3314
+ let mut carry_out = 1 ;
3315
+ let mut digit_iter = self . digits_mut ( ) . iter_mut ( ) . skip ( bit_index) ;
3316
+
3317
+ let digit = digit_iter. next ( ) . unwrap ( ) ;
3305
3318
let twos_in = negate_carry ( * digit, & mut carry_in) ;
3306
- let twos_out = if index != bit_index {
3307
- twos_in
3308
- } else if value {
3319
+ let twos_out = if value {
3320
+ // set bit
3309
3321
twos_in | bit_mask
3310
3322
} else {
3323
+ // clear bit
3311
3324
twos_in & !bit_mask
3312
3325
} ;
3313
3326
* digit = negate_carry ( twos_out, & mut carry_out) ;
3327
+
3328
+ for digit in digit_iter {
3329
+ if carry_in == 0 && carry_out == 0 {
3330
+ // no more digits will change
3331
+ break ;
3332
+ }
3333
+ let twos = negate_carry ( * digit, & mut carry_in) ;
3334
+ * digit = negate_carry ( twos, & mut carry_out) ;
3335
+ }
3336
+
3337
+ if carry_out != 0 {
3338
+ self . digits_mut ( ) . push ( 1 as BigDigit ) ;
3339
+ }
3314
3340
}
3315
3341
}
3316
3342
}
0 commit comments