Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arithmetic bit-shift on a signed integer

I am trying to figure out how exactly arithmetic bit-shift operators work in C, and how it will affect signed 32-bit integers.

To make things simple, let's say we work within one byte (8 bits):

x = 1101.0101 MSB[ 1101.0101 ]LSB 

Reading other posts on Stack Overflow and some websites, I found that: << will shift toward MSB (to the left, in my case), and fill "empty" LSB bits with 0s.

And >> will shift toward LSB (to the right, in my case) and fill "empty" bits with MS bit

So, x = x << 7 will result in moving LSB to MSB, and setting everything to 0s.

1000.0000 

Now, let's say I would >> 7, last result. This would result in [0000.0010]? Am I right?

Am I right about my assumptions about shift operators?

I just tested on my machine, **

int x = 1;   //000000000......01  x = x << 31; //100000000......00  x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!)  

Why?

like image 843
newprint Avatar asked Oct 24 '10 19:10

newprint


People also ask

Can you bit shift an integer?

Logical bit shifting may be useful for multiplying or dividing unsigned integers by powers of two. For example, if the value "0001" or "1" is shifted left, it becomes "0010" or "2," shifted to the left again it becomes "0100," or "4." Shifting to the right has an opposite effect of dividing the value by two per shift.

Which left shift operation works on signed numbers?

For signed numbers, the sign bit is used to fill the vacated bit positions. In other words, if the number is positive, 0 is used, and if the number is negative, 1 is used.

What is an arithmetic binary shift?

An arithmetic logic unit is also capable of “binary shifting”. That is moving the binary digits in the accumulator to the left or right a given number of spaces. In effect this either multiplies or divides the number by a factor of two, but in reality it is used to access and change individual bits in a series.

How do you do the arithmetic right-shift?

The result of a Right Shift operation is a division by 2n , where n is the number of shifted bit positions. Example: If we have the binary number 01110101 (117 decimal) and we perform arithmetic right shift by 1 bit we get the binary number 00111010 (58 decimal). So we have divided the original number by 2.


2 Answers

Right shift of a negative signed number has implementation-defined behaviour.

If your 8 bits are meant to represent a signed 8 bit value (as you're talking about a "signed 32 bit integer" before switching to 8 bit examples) then you have a negative number. Shifting it right may fill "empty" bits with the original MSB (i.e. perform sign extension) or it may shift in zeroes, depending on platform and/or compiler.

(Implementation-defined behaviour means that the compiler will do something sensible, but in a platform-dependent manner; the compiler documentation is supposed to tell you what.)


A left shift, if the number either starts out negative, or the shift operation would shift a 1 either to or beyond the sign bit, has undefined behaviour (as do most operations on signed values which cause an overflow).

(Undefined behaviour means that anything at all could happen.)


The same operations on unsigned values are well-defined in both cases: the "empty" bits will be filled with 0.

like image 102
Matthew Slattery Avatar answered Nov 09 '22 23:11

Matthew Slattery


Bitwise shift operations are not defined for negative values

for '<<'

6.5.7/4 [...] 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.

and for '>>'

6.5.7/5 [...] If E1 has a signed type and a negative value, the resulting value is implementation- defined.

It's a waste of time to study the behaviour of these operations on signed numbers on a specific implementation, because you have no guarantee it will work the same way on any other implementation (an implementation is, for example, you compiler on your computer with your specific commad-line parameters).

It might not even work for an older or a newer version of the very same compiler. The compiler might even define those bits as random or undefined. This would mean that the very same code sequence could produce totally different results when used across your sources or even depend on things like assembly optimisation or other register usage. If encapsulated in a function it might not even produce the same result in those bits on two consecutive calls with the same arguments.

Considering only non-negative values, the effect of left shifting by 1 (expression << 1) is the same as multpliying the expression by 2 (provided expression * 2 does not overflow) and the effect of right shifting by 1 (expression >> 1) is the same as dividing by 2.

like image 35
pmg Avatar answered Nov 09 '22 21:11

pmg