Signed/Unsigned

0

This article tries to give an insight into java numerical types and how a signed type can be converted into unsigned type.A signed number is a negative number whereas unsigned number can be positive or zero.

2’s complimentary

All numeric data types in Java are signed which means the type used to represent the number accommodates negative numbers as well as positive and zero. A negative number is represented in 2’s complimentary method. In two’s-complement, negating a number (whether negative or positive) is done by inverting all the bits and then adding 1 to that result.

byte and int

The fundamental integer data type in Java is the int, a 4-byte, big-endian, two’s complement integer. Other data type that is often used in Java is bytes. byte is an 8-bit, two’s complement integer that ranges from -128 to 127.

What happens when a byte with value > 127 enters into java world? For example, a byte value 1010 1001 which is 169 in decimal. How would Java world interpret it? Since the most significant bit is a sign bit, we will apply 2’s complimentary to it to know the actual value.

1’s complimentary of 1010 1001 is 0101 0110. Add 1 to it we get 0101 0110 + 1 = 0101 0111 = 87. Thus Java would interpret 169 as -87.

We can convert -87 back to its original unsigned value by reapplying the 2’s complimentary to it. The 2’s compliment of this number would be invert of ~87 + 1 = 1010 1000 + 1 = 1010 1001 = 169

How do we convert it programmatic? If byte value is promoted to an int (32 bits), the higher order bits will be padded with 0 and we will get a different value = 0000 0000 0000 10101001 = 169

How do we promote the byte value to an int?

Lets look at some examples.

    • A simple type cast byte to int
public void testByteToIntBySimpleAdd() {
        byte byteValue = -87;
        int intValue = 0 + byteValue;
        assertEquals(169, intValue);
    }

junit.framework.AssertionFailedError: expected:<169> but was:<-87> This still returns -87.

    • An int operation like adding 0 to the byte
    public void testByteToIntByTypeCast() {
        byte byteValue = -87;
        int intValue = byteValue;
        assertEquals(169, intValue);
    }

junit.framework.AssertionFailedError: expected:<169> but was:<-87> From the above two examples,we can confirm java treats a numeric type as signed. The only exception is char which is a 2 byte unsigned representation of unicode.

    • One can convert signed to unsigned using the below simple formulae.

int unsignedByte = signedByte >= 0 ? signedByte : 256 + signedByte;

    public void testByteToIntAdd256() {
        byte byteValue = -87;
        int intValue = byteValue >= 0 ? byteValue : 256 + byteValue;
        assertEquals(169, intValue);
    }
  • When a value is ANDed with a 1, the result is simply the original value, as in: Y AND 1 = Y So if we a byte value is ANDed with an int value, we will get the same bits padded with 0’s at the high order bits. We will use this to promote a byte to int. Thus 0000 0000 1111 1111 & 1010 1001 = 0000 0000 1010 1001
    public void testByteToIntByAndOperation() {
        byte byteValue = -87;
        int intValue = 0xFF & byteValue;
        assertEquals(169, intValue);
    }

This passes fine.

  • Another way would be to achieve the above in two steps: 0000 0000 0010 1001 + 0000 0000 1000 0000 = 0000 0000 1010 1001
    First step: Apply AND operation on -87 using mask 0111 1111, this will eliminate the highest bit which is the negative sign
    0111 1111 & 1010 1001 = 0010 1001

    byte b = -87; 
    int maskHighestBit = 0x7f & b; 
    

    This results in maskHighestBit=0000 0000 0010 1001
    Second Step: Apply AND operation on -87 using mask 1000 0000, this will eliminate the all lower bits except the highest bit.
    1000 0000 & 1010 1001 = 1000 0000

    int maskLowerBits = 0x80 & b; 
    

    This results in maskLowerBits=0000 0000 1000 0000
    Third Step: We will add result obtained in first step to second step.
    0000 0000 0010 1001 + 0000 0000 1000 0000 = 0000 0000 1010 1001
    Since each operation has promoted the value to int the final value would be 169.
    int unsignedValue = maskHighestBit + maskLowerBits

        public void testByteToIntByAndOperationInTwoSteps() {
        byte byteValue = -87;
        int intValue = 0x7f & byteValue;
        intValue += (0x80 & byteValue);
        assertEquals(169, intValue);
    }
  • Using the one of the above method, lets try to convert a signed int into unsigned int.
    public void testConvertSignedIntToUnsigned1() {
        int signedInt = -87;
        long unsignedLong = signedInt & 0xFFFFFFFFL;
        assertEquals(4294967209L, unsignedLong);
    }

In order to convert a signed type to unsigned, we need to apply AND operation on a signed type larger than the original unsigned type.

Share.

Leave A Reply