@@ -3598,19 +3598,17 @@ fn int_to_bits(
35983598 let mut bytes = int_to_bytes ( value, endianness, signed) ;
35993599 let bytes_size = bytes. len ( ) * 8 ;
36003600
3601- // There are 3 cases, which are easier to handle separately by endianness
3602- // If the size of the bigint bytes equals the expected bits, we can return them as-is
3603- // If there are more bits than we need, we need to trim some of the most significant bits.
3604- // E.g. `6:3` yields one byte of which we need to trim the 5 most significant bits.
3605- // Values like 999:3 are illegal and caught by the guard at the start of the function.
3606- // If there are fewer bits than we need, we need to add some.
3607- // E.g. `6:13` yields one byte which we need to pad with 5 bits
36083601 let bits = match ( endianness, bytes_size. cmp ( & size) ) {
36093602 ( _, Ordering :: Equal ) => BitVec :: from_vec ( bytes) ,
36103603
3604+ // Even though we return an error if `value` cannot be represented in `size` bits,
3605+ // we may need to slice off up a couple bits if the read size is not a multiple of 8.
3606+ // <3:4> yields the bytes [0b0000_0011]. We slice off 4 bits and get 0011
36113607 ( Endianness :: Big , Ordering :: Greater ) => {
36123608 BitVec :: from_bitslice ( & bytes. view_bits ( ) [ bytes_size - size..] )
36133609 }
3610+ // If the number needs fewer bits than the read size, we pad it.
3611+ // <3:9> yields the bytes [0b0000_0011]. We add one digit and get 0_0000_0011
36143612 ( Endianness :: Big , Ordering :: Less ) => {
36153613 let mut bits = BitVec :: repeat ( pad_digit, size - bytes_size) ;
36163614 bits. extend_from_raw_slice ( & bytes) ;
@@ -3782,29 +3780,36 @@ fn representable_with_bits(value: &BigInt, bits: u32, signed: bool) -> bool {
37823780 if bits == 0 {
37833781 return false ;
37843782 } ;
3785- let is_negative = value. sign ( ) == Sign :: Minus ;
3786- if is_negative && !signed {
3787- return false ;
3788- }
37893783
3790- let bits_unsigned = value. bits ( ) ;
3791- let required_bits = if !signed {
3792- bits_unsigned
3793- } else if !is_negative {
3794- // The minimal representation of an unsigned number always has 1 as its most
3795- // significant bit and thus always needs an extra bit for the sign.
3796- bits_unsigned + 1
3797- } else if let Some ( trailing_zeros) = value. trailing_zeros ( ) {
3798- // Negative powers of two don't need an extra sign bit. E.g. `-2 == 0b10`
3799- let is_power_of_2 = trailing_zeros == bits_unsigned - 1 ;
3800- bits_unsigned + ( !is_power_of_2 as u64 )
3801- } else {
3802- // The value is 0
3803- 1
3784+ let required_bits = match ( value. sign ( ) , signed) {
3785+ // Zero always needs one bit.
3786+ ( Sign :: NoSign , _) => 1 ,
3787+
3788+ // `BigInt::bits` does not consider the sign!
3789+ ( Sign :: Plus , false ) => value. bits ( ) ,
3790+ // Therefore we need to add the sign bit here: `10` -> `010`
3791+ ( Sign :: Plus , true ) => value. bits ( ) + 1 ,
3792+
3793+ // A negative number must be signed
3794+ ( Sign :: Minus , false ) => return false ,
3795+ ( Sign :: Minus , true ) => {
3796+ let bits_unsigned = value. bits ( ) ;
3797+ let trailing_zeros = value
3798+ . trailing_zeros ( )
3799+ . expect ( "trailing_zeros to return a value for non-zero numbers" ) ;
3800+ let is_power_of_2 = trailing_zeros == bits_unsigned - 1 ;
3801+
3802+ // Negative powers of two don't need an extra sign bit. E.g. `-2 == 0b10`
3803+ if is_power_of_2 {
3804+ bits_unsigned
3805+ } else {
3806+ bits_unsigned + 1
3807+ }
3808+ }
38043809 } ;
38053810
38063811 match required_bits. to_u32 ( ) {
3807- Some ( r ) => bits >= r ,
3812+ Some ( required_bits ) => bits >= required_bits ,
38083813 None => false ,
38093814 }
38103815}
@@ -3846,6 +3851,18 @@ mod representable_with_bits_test {
38463851 assert ! ( !representable_with_bits( & BigInt :: from( -9 ) , 3 , true ) ) ;
38473852 }
38483853
3854+ #[ test]
3855+ fn zero_representable_with_bits_test ( ) {
3856+ for i in 0 ..12 {
3857+ println ! ( "{i}: {}" , BigInt :: from( i) . bits( ) ) ;
3858+ }
3859+ assert ! ( !representable_with_bits( & BigInt :: ZERO , 0 , false ) ) ;
3860+ assert ! ( !representable_with_bits( & BigInt :: ZERO , 0 , true ) ) ;
3861+
3862+ assert ! ( representable_with_bits( & BigInt :: ZERO , 1 , false ) ) ;
3863+ assert ! ( representable_with_bits( & BigInt :: ZERO , 1 , true ) ) ;
3864+ }
3865+
38493866 #[ test]
38503867 fn number_representable_with_sign_test ( ) {
38513868 // Sign needs one additional bit
0 commit comments