|
|
In this example, we used an int. You can also shift bytes, shorts, chars, and longs. Bytes, chars, and shorts are promoted to ints before being shifted. Floats, doubles, and booleans cannot be shifted.
Making Floats from Bits
If you really need to create a float from a series of bits, there are a couple of workarounds. You can shift the bits around in an int and use the static java.lang.Float.intBitsToFloat() method to convert the int into a float. For example, suppose data is a byte array with four components that correspond to the four bytes in a float. (Youll see exactly this in Chapter 4.) You can read the float out of the byte array by first shifting the bytes into an int called bits and then calling the java.lang.Float. intBitsToFloat(int bits) method like this:
int bits = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
float f = Float.intBitsToFloat(bits);
You can make doubles from longs in a similar fashion with the java.lang.Double.longBitsToDouble(long bits) method.
long bits = (long) data[0] << 56 | (long) data[1] << 48
| (long) data[2] << 40 | (long) data[3] << 32
| (long) data[4] << 24 | (long) data[5] << 16
| (long) data[6] << 8 | (long) data[7];
double d = Double.longBitsToDouble(bits);
Alternately, you can construct a ByteArrayInputStream from the byte array, chain the ByteArrayInputStream to a DataInputStream, and then call the readFloat() or readDouble() method of the DataInputStream. For example,
ByteArrayInputStream bis = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bis);
float f = dis.readFloat();
In most Java implementations, this is less efficient than the first alternative. However, it produces slightly more intelligible code.
|
The >> operator shifts numbers to the right with sign extension. This means that vacated bits on the left are filled with the sign bit: 0 for a positive number or 1 for a negative number. Otherwise, right shifts carry the same caveats as left shifts: The left side must be an integral type and will be promoted to an int if necessary before shifting. The left side must be between 0 and 31 (0 to 63 if the left hand sides a long) and will be truncated to that value if necessary. For example, the int -23 is, in binary notation, 11111111111111111111111111101001. Table 2-9 shows what you get when this is right shifted by various numbers of bits. Note that the vacated spots are filled with sign bits and that right shifting is equivalent to division by two.
Table 2-9 Right-shifting -23
|
Value
| Bit Pattern
|
|
-23
| 11111111111111111111111111101001
|
-23 > 1 = -12
| 11111111111111111111111111110100
|
-23 > 2 = -6
| 11111111111111111111111111111010
|
-23 > 3 = -3
| 11111111111111111111111111111101
|
-23 > 4 = -2
| 11111111111111111111111111111110
|
-23 > 5 = -1
| 11111111111111111111111111111111
|
-23 > 6 = -1
| 11111111111111111111111111111111
|
|
Sometimes you dont want to fill with the sign bits, but rather with 0. The >>> operator does an unsigned shift right. In other words, it fills the vacated spaces with zeroes regardless of the sign bit. Table 2-10 demonstrates this.
Table 2-10 Unsigned right-shifting of -23
|
Value
| Bit Pattern
|
|
-23
| 11111111111111111111111111101001
|
-23 >> 1 = 2,147,483,636
| 01111111111111111111111111110100
|
-23 >> 2 = 1,073,741,818
| 00111111111111111111111111111010
|
-23 >> 3 = 536,870,909
| 00011111111111111111111111111101
|
-23 >> 4 = 268,435,454
| 00001111111111111111111111111110
|
-23 >> 5 = 134,217,727
| 00000111111111111111111111111111
|
-23 >> 6 = 67,108,863
| 00000011111111111111111111111111
|
|
The >>=, <<=, and >>>= behave as you might expect, shifting the left argument by the number of bits specified in the right argument and in the direction specified by the operator, and then assigning the result to the left side.
|