Follow Me On...

JAVA has no Unsigned Byte!!#$@$@#

Personally, i think in unsigned bytes…
Recently, i got involved in a project that we used Java for… but i ended up having to do a lot of low level bit packing and creating CRCs, etc.

At first when i realized that Java had no unsigned byte i started looking all over the web for an unsigned byte class. I found a few… but it wasn’t what i wanted. In the end i just faced my fear and started messing around with it… and what better way to do so but create a quick unit test TestCase.

if you read this poorly written unit test it might demystify things for you . If not, let me know what it needs to make you understand.

/*
 * @author Blake Robertson (blaker@ieee.org)
 * Created on Jan 22, 2006
 *
 * Using this test case i came to the following conclusions about 
 * when you can and when you can't use the java byte primitive when
 * what you really want is a unsigned byte.
 * 
 * CONCLUSIONS
 * 1) If you want an unsigned byte and plan to use it to do arthmetic
 *    then don't!  Because, once you get to 128 you no longer have a positive number
 *    you are doing math with...  so what i do is i just use int's instead
 *    and i'm careful about not letting the value get bigger then 255.
 *    
 * 2) Casting to byte does what it should... so if you have
 *    byte x = (byte) 0x23426463498242343699
 *    x= 0x99 (it always equals the lowest byte, the rest is trunkcated).
 * 
 * 
 * 3) If you are only doing bit manipulation... then you are okay.
 *    you don't have to think about whether or not you are manipulating 
 *    a signed or unsigned byte.... but if you have to print that number out
 *    then you might have a problem or if you need to compare that number.
 *    
 * 
 * 4) So downcasting works like we want it to... we get whatever the lower
 *    byte is of int.  So, i tested upcasting like from a byte to an int.
 *    Does it perform a sign extention or does it simply take the 1 byte that
 *    is set in the byte and set it in the int.  
 *       Ans: it does sign extention so it keeps the number the same.
 *       EX: So for example byte b = -1 ... 
 *             assertTrue( -1 == (int) b ); // doesn't cause errors (see one of     the test cases below).
 *    
 *    
 *
 *
 *
 *
 */
package com.blakerobertson.test;

import com.blakerobertson.util.ByteUtil;

import junit.framework.TestCase;

/**
 * Filename: JavaBitManipulationTestCase.java <BR>
 * Date Created: Jan 22, 2006  <BR>
 * <P>
 * 
 * <P>
 * @author blake
 * @version 1.0
 *
 */
public class JavaBitManipulationTestCase extends TestCase {

    public void testWhatCastingDoes() {
        
        int xInt = 0xFFFFFFFF;
        
        short xShort = (short) xInt;
       
        assertFalse( xShort == 0xFFFF );
        assertTrue( xShort == (short) 0xFFFF );
        assertTrue( xShort == ByteUtil.convertToSignedShort( 0xFFFF ).shortValue() );

        // So, the cast is done properly... meaning the lower two bytes of it are
        // set to the shorts 2 bytes... but when you want to actually print or compare the 
     }
    
    public void testFlippingSignBit() {
        byte x = 0;
        byte y;
        
        x = (byte) ( x  | 0x80);        
        y = (byte) 0x80;
        
        assertTrue( x == y );
    }
    
    public void testCasting2() {
        
        int x = 255;
        int xTwos = ~255 + 1;
       
        int negX = -1;
        int negXTwos = ~negX + 1;
        
        
        // if the bits don't get changed when you cast it to a lower type at all.
        // Then if i take 255 which is (1111 1111)base2 when i case it to a byte
        // it should be equal to -1.
        
        byte isNegOne = (byte) x;
        byte negOne = -1;
        assertTrue( negOne == isNegOne );
         
    }
    
    public void testIncrementingOverflow() {
        
        byte x = 125;
 
        // NO Exception is called... which was a suprise to me...
        
//        try {
            x++; // x = 126
            x++; // x = 127
            x++; // x = 128
            
            assertTrue( x == (byte) 128 );
//        }
//        catch (Exception e) {
//            return;
//        }
    }
    
    public void testIsConvertToSignedByteUseless() {
        
        for( int i=0; i < 256; i++ )
        {
            assertTrue( (byte) i == ByteUtil.convertToSignedByte( i ).byteValue() );
        } 
    }
    
    
    public void testNeedToConvertWhenByteShouldBeUnsigned() {
        
        byte x = (byte) 200;
        short y = 200;
        int rand = 342;
        
        assertFalse( (rand ^ x ) == (rand ^ y) );
        // TODO determine why the assertion below fails
        //  assertTrue( (rand ^ ByteUtil.convertToUnsignedByte(x) ) == (rand ^ y) );
        
    }
    
    public void testCastByteToInt() {
        byte theByte = (byte) 0xFF;
        
        System.out.println("theByte == " + theByte	); // prints theByte == -1
        
        int theInt = (int) theByte;
        
        assertFalse( theInt == 255 );
        assertTrue( theInt == -1 );        
        
    }
    
    
    public static void main(String[] args) {
        junit.swingui.TestRunner.run(JavaBitManipulationTestCase.class);
    }

}