How to Bit Shift a Long by More Than 32 Bits

How do I bit shift a long by more than 32 bits?

Re-try this using a variable of type uint64_t (from stdint.h) instead of long. uint64_t is guaranteed to be 64 bits long and should behave as you expect.

How to shift 32 bit int by 32 (yet again)

In Java it's guaranteed to work if those variables are of type int, since >> in Java does an arithmetic right shift and shifting more than 31 also has defined behavior. But beware of operator precedence

int lshift(int x, int n)
{
return (x << n) & ((n-32) >> 5);
}

This will work for shift count up to 32. But it can be modified to include any int values with shift counts larger than 31 return 0

return (x << n) & ((n-32) >> 31);

However in C and C++ the size of int type and the behavior of >> operator is implementation defined. Most (if not all) modern implementations implement it as arithmetic shift for signed types though. Besides, the behavior of shifting more than the variable width is undefined. Worse yet, signed overflow invokes UB so even a left shift by 31 is also UB (until C++14). Therefore to get a well defined output you need to

  • Use a unsigned fixed-width type like uint32_t (so x << 31 isn't UB)
  • Use a compiler that emits arithmetic right shift instruction for >> and use a signed type for n, or implement the arithmetic shift yourself
  • Mask the shift amount to limit it to 5 bits for int32_t

The result would be

uint32_t lshift(uint32_t x, int32_t n)
{
return (x << (n & 0x1F)) & ((n-32) >> 31);
}

If the architecture supports conditional instructions like x86 or ARM then the following way may be faster

return n < 32 ? x << n : 0;

On a 64-bit platform you can made this even simpler by shifting in a 64-bit type and then mask. Some 32-bit platforms like ARM does support shifting by 32 so this method is also efficient

return ((uint64_t)x << (n & 0x3F)) & 0xFFFFFFFFU;

You can see the output assembly here. I don't see how it can be improved further

Does bit-shifting in C only work on blocks of 32-bits

In your setup the constant 1 is a 32 bit integer. Thus the expression 1 << testBin operates on 32 bits. You need to use a 64 bit constant to have the expression operate on 64 bits, e.g.:

x = (uint64_t)1 << testBin;

This does not change the fact that shifting by 240 bits is formally undefined behavior (even though it will probably give the expected result anyway). If testBin is set to 48, the result will be well-defined. Hence the following should be preferred:

x = (uint64_t)1 << (testBin % 64);

Is Shifting more than 32 bits of a uint64_t integer on an x86 machine Undefined Behavior?

The standard says (6.5.7 in n1570):

3 The integer promotions are performed on each of the operands. The type of the result is
that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2 , reduced modulo
one more than the maximum value representable in the result type. If E1 has a signed
type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is
the resulting value; otherwise, the behavior is undefined.

5 The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type
or if E1 has a signed type and a nonnegative value, the value of the result is the integral
part of the quotient of E1 / 2E2 . If E1 has a signed type and a negative value, the
resulting value is implementation-defined.

Shifting a uint64_t a distance of less than 64 bits is completely defined by the standard.

Since long long must be at least 64 bits, shifting long long values less than 64 bits is defined by the standard for nonnegative values, if the result doesn't overflow.

Note, however, that if you write a literal that fits into 32 bits, e.g. uint64_t s = 1 << 32 as surmised by @drhirsch, you don't actually shift a 64-bit value but a 32-bit one. That is undefined behaviour.

The most common results are a shift by shift_distance % 32 or 0, depending on what the hardware does (and assuming the compiler's compile-time evaluation emulates the hardware semantics, instead of nasal demons.)

Use 1ULL < 63 to make the shift operand unsigned long long before the shift.

Can't bitshift a char more than 32 bits into unsigned long long

text[ii] is a single char which will be promoted to int to perform binary operation. It is not possible to shift a bit more then the width.

You can easily detect it with compiler warning: Live

To solve the problem you can simply cast the type:

char a='a';
uint64_t x = (uint64_t)a<<45;

Bit shifting for 32 bit long

The type of decryptedVCW[2] & 0xff is int, since the first operand is byte and the second is an int literal.

When the first operand of the << operator is int, you are shifting an int, so if the second operand is 32, you'll get int overflow.

You can cast the first operand of the << operator to long :

(((long)(decryptedVCW[2] & 0xff)) << 32)

or you can force the first operand to be a long by using a long literal in the & operation, as suggested by @shmosel :

(decryptedVCW[2] & 0xFFL) << 32

Shifting a long by more than 31 bits (java)

The problem you're running into is that your operation breaks down like this:

l |= 0b1 << 37;

Turns into, in sequence:

int _temp = 1 << 37;
l |= (long) _temp;

The reason it's like that is because 0b1, or any numeric literal that lacks a decimal part and a trailing letter to indicate what kind of literal you want (D/F/L for double/float/long), is therefore an int, period. You then left-shift this int value (1; 0b1 is just a weird way to write 1 after all) by 37. The spec of left-shift states that the right-hand operator of a shift operation only considers the lower 5 bits for int shifts and the lower 6 for long shifts. Because otherwise you'd just be making the value 0. Thus, someInt << 37 is a weird way of writing someInt << 5.

The solution is to make sure that your shift operation is actually happening on longs. There are many, many ways to make that happen.

Use a long literal

By writing a trailing L. It can be written in either case, but style guides and developers will egg your house if you use a lowercase l because duh that is incredibly stupid, don't do that. It looks like a 1. Thus:

l |= 1L << 37; // or if you must, 0b1L works too

One step at a time.

long temp = 1;
temp <<= 37;
l |= temp;

Cast it

l |= ((long) 0b1) << 37;

These will all get the job done: They all end up having the << operation be in 'long mode' (which occurs if the LHS is of type long, which it is, in all these 3 examples).

How to left-shift numbers greater than 32-bits?

Just do what the math of a left shift does:

Arithmetic shifts are equivalent to multiplication by a positive (to the left) or by a negative number (to the right), integral power of the radix (e.g. a multiplication by a power of 2 for binary numbers).

function shift(number, shift) {
return number * Math.pow(2, shift);
}

shift(192, 24)
//3221225472

shift(3221225472, -24)
//192

Why doesn't left bit shift shift beyond 31 for long int datatype?

Although your x is of type long int, the 1 is not. 1 is an int, so 1<<63 is indeed undefined.

Try (static_cast<long int>(1) << 63), or 1L << 63 as suggested by Wojtek.



Related Topics



Leave a reply



Submit