Bitwise shift with unsigned long over 2^31


I was trying some stuff with bitwise operations and I’ve found something intriguing.
Has anyone already encountered this problem before ?

Thanks for your replies :slight_smile:

unsigned long i;

i = -1;			// 18446744073709551615 = 2^64-1, normal

i = 1<<30;		// 1073741824 = 2^30, normal

i = 1<<31;		// 18446744071562067968 = 2^64 - 2^31 != 2^31. Weird ?

i = 1<<32;		// 0. Weird ?
i = 1<<33;		// 0. Weird ?

Replace “1” in all your examples with “1ull” or “((uint64_t) 1)”

Basically, the mistake you made was that all your calculations are done with signed 32 bits ints, and only converted to unsigned 64 bits in the end.

1 Like

I didn’t comment on that, but since you do, let’s go :slight_smile:

The “unsigned long” type in C++ is only specified to have at least 32 bits. As shown by CG_LSD in the comments, on his platform “unsigned long” take 64 bit values. Hence the rest of his code should work as expected with the corrections I suggest.

In any case, to make it more less confusing I also prefer to use the “int64_t” type notations.

Yeah you’re right, my compiler bias is showing.

Genuine curiosity : is all this linked to compiler choices, OS choices or processor architecture ?

It’s entirely dependent on the compiler, which may or may not take the architecture into account. For instance MSVC has fixed sizes no matter what.

Thanks @pb4 and @reCurse !

Are there other things that are compiler-dependent ?
I wanna be as careful as possible

Yeah, quite a number of things actually, the vast majority of which probably don’t matter in everyday use. It would not be practical, helpful or even feasible to try to list them.

1 Like