Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which way is better to get lower 32 bits of a 64 bits integer

Tags:

c++

I found that in some answers they recommended using

lower = (some_var << 32) >> 32;

But I tested and found the following is faster:

lower = some_var & 0xffffffff;

So which is better? Is the former safer in some cases or faster after compiler optimized?

like image 504
MoorLi Avatar asked Mar 20 '15 05:03

MoorLi


People also ask

What is the difference between 32-bit and 64-bit integer?

A 32 bit Signed Integer can house a number from −2,147,483,648 to 2,147,483,647 Unsigned: 0 to 4,294,967,295. A 64 bit Signed Integer can house a number from −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 Unsigned: 0 to 18,446,744,073,709,551,615.

How many more values can be stored in a 64-bit integer than in a 32-bit integer?

A 32-bit number can store 2^32 values, or 4,294,967,296. Meanwhile, a 64-bit number has 2^64 possible values, or a staggering 18,446,744,073,709,551,616.

How many integers is 32 bits?

An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295]. The signed integer is represented in twos complement notation.


3 Answers

Masking with & is better:

  • & is reliable for signed and unsigned some_var, while bitshifting right a negative number produces an implementation defined result:

The value of E1 >> E2 is E1 right-shifted E2 bit positions. [...] If E1 has a signed type and a negative value, the resulting value is implementation-defined.

  • on every CPU I've ever known (Z80, 6502C, x86, 68000, UltraSparc), bitwise-AND is a single CPU instruction and takes one clock cycle... it's extremely unlikely to be slower or take more bytes of machine code than the bit-shifting approach you mention, though the compiler might optimise that to a bitwise AND anyway.

The one disadvantage of masking is that it's relatively easy to accidentally have 7 or 9 Fs, whereas a typo in 32 is obvious: there are other ways to generate the masking value though, e.g. (1LL<<32)-1, or the hackish but somehow elegant uint32_t(-1).

Of course, if lower is uint32_t and some_var uint64_t, you can just let the conversion be implicit, so the optimiser doesn't even need to realise the bitwise-AND can be removed before assignment, but that might give you a compiler warning, which you can silence ala...

uint32_t lower = static_cast<uint32_t>(some_var);

The masking is mainly useful when assigning to another uint64_t, or when the mask isn't for all the 32 least significant bits.

like image 143
Tony Delroy Avatar answered Nov 06 '22 08:11

Tony Delroy


The masking with AND is better since it doesn't depend on the signedness of the value.

But the most efficient way to take the lower 32 bit is to assign it to a 32-bit variable.

uint64_t u = 0x1122334455667788;
uint32_t n;

n = static_cast<uint32_t>(u);  // 0x55667788

The difference to a bit-wise AND is that the CPU just takes the lower part without doing any logical operation.

If you have a 32-bit CPU it just ignores the upper value stored in a second register or memory place.

If you have a 64-bit CPU it has a single instruction to extend (unsigned) a 32 bit value to 64 bit value.

like image 21
harper Avatar answered Nov 06 '22 08:11

harper


A good optimizer would generate the same code in both cases. To me this is the most straight forward method: lower = some_var & 0xffffffff; The other form may generate unnecessary shiftage.

Sometimes I use union to overlap variables when I want to be absolutely sure the compiler doesn't mess things up.

For example:

typedef union {
    int64 QWORD;
    int32 DWORD[2];
} overlapper64;

overlapper someVariable;

Then access it as:

someVariable.QWORD;

int32 myVar32 = someVariable.DWORD[0];

Depending on platform/compiler the order in which the overlap occurs may vary. Be sure to test it on your specific platform. In C, I use a bunch of platform specific #ifdefs to control the order automatically.

like image 1
particle xlr8r Avatar answered Nov 06 '22 07:11

particle xlr8r