Jack Allan
Jack Allan

Reputation: 15014

Java bitwise operator not working as expected

The following code attempts to store 4 longs in a byte array. Random access is important which is why I'm not doing this with byte streams. Why is the below code not working? Can you think of a more efficent way to do this?

public static void storeLong(long value, byte[] buf, int offset) {
    buf[offset] = (byte) (value & 0xFFL);
    buf[offset+1] = (byte) ((value >>> 8) & 0xFFL);
    buf[offset+2] = (byte) ((value >>> 16) & 0xFFL);
    buf[offset+3] = (byte) ((value >>> 24) & 0xFFL);
    buf[offset+4] = (byte) ((value >>> 32) & 0xFFL);
    buf[offset+5] = (byte) ((value >>> 40) & 0xFFL);
    buf[offset+6] = (byte) ((value >>> 48) & 0xFFL);
    buf[offset+7] = (byte) ((value >>> 56) & 0xFFL);
}

public static long retrieveLong(byte[] buf, int offset) {
    return ((long)buf[offset]) 
        + (((long)buf[offset+1])<<8) 
        + (((long)buf[offset+2])<<16) 
        + (((long)buf[offset+3])<<24)
        + (((long)buf[offset+4])<<32) 
        + (((long)buf[offset+5])<<40) 
        + (((long)buf[offset+6])<<48) 
        + (((long)buf[offset+7])<<56);
}


public static void main(String[] args) {
    byte[] buf = new byte[32];
    storeLong(-1, buf, 0);
    storeLong(1, buf, 8);
    storeLong(Long.MAX_VALUE, buf, 16);
    storeLong(Long.MIN_VALUE, buf, 24);

    System.out.println(-1);
    System.out.println(1);
    System.out.println(Long.MAX_VALUE);
    System.out.println(Long.MIN_VALUE);

    System.out.println(retrieveLong(buf, 0));
    System.out.println(retrieveLong(buf, 8));
    System.out.println(retrieveLong(buf, 16));
    System.out.println(retrieveLong(buf, 24));

}

The output I get from the above is the following. You can see that the first four numbers do not match the next 4:

-1
1
9223372036854775807
-9223372036854775808

-72340172838076673
1
9151031864016699135
-9223372036854775808

Upvotes: 0

Views: 1725

Answers (2)

Jack Allan
Jack Allan

Reputation: 15014

I did some tests and found that using a java.nio.LongBuffer is twice as fast as my code

    ByteBuffer bb = ByteBuffer.allocate(4*8);
    LongBuffer lb = bb.asLongBuffer();

    lb.put(0, -1);
    lb.put(1, 1);
    lb.put(2, Long.MAX_VALUE);
    lb.put(3, Long.MIN_VALUE);

    System.out.println(lb.get(0));
    System.out.println(lb.get(1));
    System.out.println(lb.get(2));
    System.out.println(lb.get(3));

I can then get the byte array using bb.array()

Thanks to Louis Wasserman and Rene Jeschke for their efforts

Upvotes: 2

Neet
Neet

Reputation: 4057

Don't use + and byte is signed:

public static long retrieveLong(byte[] buf, int offset) {
    return ((long)buf[offset]     & 255) 
        | (((long)buf[offset + 1] & 255) << 8) 
        | (((long)buf[offset + 2] & 255) << 16) 
        | (((long)buf[offset + 3] & 255) << 24)
        | (((long)buf[offset + 4] & 255) << 32) 
        | (((long)buf[offset + 5] & 255) << 40) 
        | (((long)buf[offset + 6] & 255) << 48) 
        | (((long)buf[offset + 7] & 255) << 56);
}

You have to and each byte with 255 to make it 'unsigned'. Also you have to use binary or instead of add.

Upvotes: 8

Related Questions