 Java-Accessing Unsigned Data

Accessing Unsigned Data

The Java programming language does not provide direct support for unsigned numeric values (other than char). But there are many instances in which you may need to extract unsigned information from a data stream or file, or pack data to create file headers or other structured information with unsigned fields. The ByteBuffer API does not provide direct support for this, but it’s not difficult to do. You just need to be careful about precision.

Two’s Complement Representation

All of the integer types are represented by binary numbers of varying bit widths. For example, the byte value for 126 in binary is 01111110, where each position represents a power of two, starting with 2^0 or 1 at the rightmost bit. The next bit position to the left would be 2^1, or 2, continuing toward the left with 2^2, or 4, then 8, 16, 32, and so on. So 126 has 1 bits set at positions 1 to 6 (counting from 0 at the right); thus, 126 is the sum of 2^1+2^2+2^3+2^4+2^5+2^6+2^7 which is 2+4+8+16+32+64. All of the integer types (except char) are signed(negative and positive) integers. This means that they can represent negative values as well as positive ones. Java uses an encoding known as two’s complement, which means that negative numbers are represented by inverting (‘1’ changes to ‘0’ and ‘0’ changes to ‘1’) all of the bits in a value(known as one’s complement), then adding 1 to the result. For example, –126 is represented by inverting all of the bits in 126, or 01111110, which yields 10000001, then adding 1, which results in 10000010, or –126. To decode a negative number, first invert all of the bits, then add 1. For example, –126, or 10000010 inverted, yields 01111101, or 125, so when you add 1 you get 126. The reason Java (and most other computer languages) uses two’s complement is easy to see when you consider the issue of zero crossing. Assuming a byte value, zero is represented by 00000000. In one’s complement, simply inverting all of the bits creates 11111111, which creates negative zero. The trouble is that negative zero is invalid in integer math. This problem is solved by using two’s complement to represent negative values. When using two’s complement, 1 is added to the complement, producing 100000000(9 bits). This produces a 1 bit too far to the left to fit back into the byte value, resulting in the desired behavior, where –0 is the same as 0, and 11111111 is the encoding for –1. Although we used a byte value in the preceding example, the same basic principle applies to all of Java’s integer types.

Byte to Unsigned Int

Byte is a signed 8-bit type(using two’s complement to encode negative values) that has a range from –128 to 127(256 values). For positive numbers the leftmost bit is ‘0’ and for negative numbers the leftmost bit is ‘1’. Assume you have ‘150’ as an unsigned byte. That is represented as ‘10010110’. This binary value, when expressed as a signed two’s complement number, turns out to be ‘-106‘(150-256). Any unsigned byte values over 128(0 to 127) will be affected by the difference since the left-most bit is used in this way by the two’s complement scheme.

To convert a byte to an unsigned int value, use (byte value & 0xff). The hex literal 0xff is an equal int(255). Java represents int as 32 bits(00000000 00000000 00000000 11111111). When you do a bit wise AND(&) with this value(255) on any number, it is going to mask all but the lowest 8 bits of the number. The AND produces a 1 bit if both operands are also 1. A zero is produced in all other cases. When you do a bitwise AND of 0xff and any value from 0 to 255, the result is the exact same as the value. And if any value higher than 255 still the result will be within 0-255. Following methods may be useful when you must deal with unsigned data in ByteBuffer. Program

Program Source

import java.nio.ByteBuffer;

public class Javaapp {

public static void main(String[] args) {

ByteBuffer buf = ByteBuffer.allocate(12);
buf.put((byte)150);
buf.putShort((short)63000);
buf.putInt((int)3100460000L);
buf.flip();
System.out.println("Signed Byte  : "+buf.get());
System.out.println("Signed Short : "+buf.getShort());
System.out.println("Signed Int   : "+buf.getInt());
buf.flip();
System.out.println("Unsigned Byte Value From Int  : "+(buf.get()&0xff));
System.out.println("Unsigned Short Value From Int : "+(buf.getShort()&0xffff));
System.out.println("Unsigned Int Value From Long  : "+(buf.getInt()&0xffffffffL));
}
}

Unsigned Data Accessing Methods

public static short getUnsignedByte (ByteBuffer bb)
{
return (short)(bb.get() & 0xff);
}
public static int getUnsignedShort (ByteBuffer bb)
{
return (bb.getShort( ) & 0xffff);
}
public static long getUnsignedInt (ByteBuffer bb)
{
return (long)(bb.getInt( ) & 0xffffffffL);
}