Bitwise shift with unsigned long over 2^31


#1

Hello,

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 ?
...

#2

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.


#4

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.


#5

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


#6

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


#7

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.


#8

Thanks @pb4 and @reCurse !

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


#9

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.