Binary literal out of range for i32 (with negative numbers)


#1

Hi,

I’m trying to implement a fixed point type based on an i32 where the last 30 bits are the fractional bits. Things are looking good and seem to work, but the compiler warns me that the binary literals I use in the tests are out of range. I get this warning for the negative numbers, positive numbers work without warnings.

warning: literal out of range for i32
   --> src\i2f30.rs:137:46
    |
137 |         assert_eq!(I2F30::new(-5).into_raw(), 0b11100000000000000000000000000000);
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The number is meant to represent -0.5, which it to my understanding should be doing, but this warning worries me. After all, an i32 should have 32 bits and all combinations of bits ought to represent a number - then why doesn’t this do it?


#2

I may be wrong, but I think that Rust’s signed binary literals work like decimal literals, in the sense that you must put a leading minus sign in front, not write down the negative number in two’s complement representation.

If my understanding is correct, then Rust will understand your input as the positive number (2^31 + 2^30 + 2^29), which is indeed out of range for i32, whose valid values range from (-2^31) to (2^31 - 1).


#3

It seems you are right. That number should be written:

let x = -0b_0010_0000__0000_0000__0000_0000__0000_0000_i32;


#4

u32 is more appropriate for storing the raw value here since all 32 bits are being used to represent a custom encoding.


#5

Thanks HadrienG and leonardo, that did it! I would never had figured that out on my own.

Vitalyd that is a good point, thanks! I opted for i32 because I wanted negative numbers magically taken care of for me. I’m afraid of multiplication and division with u32 and my own sign representation, but maybe it isn’t too hard?


#6

You can internally use i32 (after you’ve shifted and masked as needed) if that makes things easier. The “raw” representation, which I understand as “here are the raw bits in the encoding”, is better with u32.

You can also encapsulate the raw form by returning your own opaque newtype. Then callers don’t need to see what you’re using internally. But I don’t know if that gels with your usecases.


#7

That makes a lot of sense! Thanks! :slight_smile: