1

I'm currently working a small project where I end up messing with byte, short value etc, and after some reading, I still don't understand some stuff, like what is "bit shifting", why do we use it, when do we need, and how does it work.

Also, I found this function to convert short into byte:

private byte[] short2byte(short[] sData) {
    int shortArrsize = sData.length;
    byte[] bytes = new byte[shortArrsize * 2];
    for (int i = 0; i < shortArrsize; i++) {
        bytes[i * 2] = (byte) (sData[i] & 0x00FF);
        bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
        sData[i] = 0;
    }
    return bytes;

}

I think I understand this function but my problem is that I'm not sure what these two lines are doing:

bytes[i * 2] = (byte) (sData[i] & 0x00FF);
bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);

I think it has something to do with bit shifting, so can someone please explain what that means? If you have a link or good documentation regarding bytes, short, bit shifting etc, please include that if possible.

Kind regards

John Hoerr
  • 7,955
  • 2
  • 30
  • 40
murielK
  • 1,000
  • 1
  • 10
  • 21
  • 2
    You should really, really, learn what the Java operators do - there are only so many. +,-,* and / isn't just enough. – Ingo Feb 05 '14 at 15:33

3 Answers3

3

So first one: Bit Shifting

I guess you've heard about binary numbers. Most people nowadays use the decimal number system in our day-to-day business, where you have digits ranging from 0-9. Every number you use is made up of digits from 0-9. The binary system only uses the digits 0 and 1, which is very convenient for computer to use since then you can represent numbers with power easily:

0 = no power

1 = power

Same as the decimal number system you can make larger numbers just by putting digits next to each other: in decimal 10 is 9+1. In binary 10 is 1+1.

Binary = Decimal
0   = 0
1   = 1
10  = 2
11  = 3
100 = 4
101 = 5
110 = 6
111 = 7

and so on.

Computers usually work with fixed-length numbers (at least with integer-type nubers, like int, long, short, byte, ...), so they fill all remaining digits on the left with 0:

5 in decimal = 101 in binary = 00000101 in 8-bit (byte) = 0000000000000101 in 16-bit (short)

and so on.

What bit shifting does is it moves all bits into one direction:

Right-Shift by two digits:
00001101 >> 2 = 00000011

Left-Shift by three digits:
00001101 << 3 = 01101000

A left shift is equivalent to multiplying by 2 while a right shift equivalent to dividing by 2 (talking about positive numbers here, since negative numbers are a bit different).

Now to the second one: Masking This is now about this part: sData[i] & 0x00FF

At first, here we have another numbers notation: the hexadecimal numbers. It works quite similarly as the binary numbers just now there are 16 different digits: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. Each of them stands for four digits in binary, so you can convert between the two by just replacing each digit by the following digits:

Hex = Binary
0   = 0000
1   = 0001
2   = 0010
3   = 0011
4   = 0100
5   = 0101
6   = 0110
7   = 0111
8   = 1000
9   = 1001
A   = 1010
B   = 1011
C   = 1100
D   = 1101
E   = 1110
F   = 1111

So the number given here as 0x00FF equals 0000000011111111 in 16-bit binary.

Now to the &, or the actual masking. The &-Operator returns 1 for every bit where both inputs are 1 and 0 for each bit where either of the inputs are 0:

0101010101010101
&
0000000011111111
=
0000000001010101

So you see, you can use the &-operator to mask out all the bits that are 0 in the one input-string.

So what that part of the function does is it splits the short (which is 16-bit long) into two separate 8-bit-bytes. Lets say sData[i] contains this number: 0011001101010101

bytes[i * 2] = (byte) (sData[i] & 0x00FF);
=
bytes[i * 2] = (byte) (0011001101010101 & 0000000011111111);
=
bytes[i * 2] = (byte) (0000000001010101); //lower 8 bit



bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
=
bytes[(i * 2) + 1] = (byte) (0011001101010101 >> 8); //Right shift by 8 spaces
=
bytes[(i * 2) + 1] = (byte) (0000000000110011); //upper 8 bit
Dakkaron
  • 5,930
  • 2
  • 36
  • 51
2

The two lines in question actually splits a short value to 2 byte values. If you have short variable n = 0xCCDD, The line bytes[i * 2] = (n & 0x00FF) extracts the least significant byte to bytes[i *2] ie. Stores 0xDD in bytes[i * 2]

The line bytes[i * 2 + 1] = (n >> 8), shits 8 bytes to the right and gives the value of most significant byte in n ie. Stores 0xCC in bytes[i * 2 + 1]

Having a look in to http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html will help understand it better.

2

Bit shifting is simply shifting the position of the 1s in a number's representation. For example:

0001101 // This is the binary representation of 13
0011010 // This is 13 << 1, or 26, or 13 * 2
0000110 // This is 13 >> 1, or 6, or floor(13 / 2)

0110100 // 13 << 2 = 52 = 13 * 2^2
1101000 // 13 << 3 = 104 = 13 * 2^3

0000011 // 13 >> 2 = 3 = floor(13 / 2^2)
0000001 // 13 >> 3 = 1 = floor(13 / 2^3)

The other line you're confused about is "bitwise and"; A & B results in the number with 1s in all of the positions in which both A and B have 1s:

  1011010 //  90
& 0000011 // & 3
--------- // ---
  0000010 //   2
//     ^---- This is the only position where both 90 and 3 have a 1
Brian S
  • 4,878
  • 4
  • 27
  • 46