0

SO, I'm playing around with an idea. I'm trying to convert primitives to and from a char array for file logging. I've got all the details worked out, but I don't understand something.. Take the following case, for example:

public static byte[] ToByta (short data) {
	return new byte[]{
		(byte)(data & 0xff),
		(byte)((data >>> 8) & 0xff)
	};
}

The above converts a short value to a 2-byte byte array using bitwise operators.

Let's test it out:
0 yields {0, 0}
10 yields {10, 0}
-10 yields {-10, -1}
127 yields {127, 0}
128 yields {-128, 0}
1234 yields {-46, 4}
-1234 yields {46, -5}

Everything looks normal.
Now, lets pass those arrays through the original reverting function:

public static short ToShort (byte[] data) {
	if (data == null) return 0x0;
	if (data.length != 2) return 0x0;
	return (short) (
		data[0]        |
		data[1] << 8
	);
}

Can you see anything wrong with that? Maybe.

Let's test it out:
0 yields 0
10 yields 10
-10 yields -10
127 yields 127
128 yields -128
1234 yields -46
-1234 yields 1234

As you can see, there's a few issues. I knew it had something to do with the bits, so I played around a bit and came up with this:

public static short ToShort (byte[] data) {
	if (data == null) return 0x0;
	if (data.length != 2) return 0x0;
	return (short) (
		0xff           &
		data[0]        |
		data[1] << 8
	);
}

Which seems to work perfectly.
All I added was the 0xff & in the combination sequence.. And I don't know why this works whereas it doesn't work without the 0xff & .

Can someone please explain that to me?

10101010

does not equal

11111111 &
10101010

??? :-|

6
Contributors
9
Replies
10
Views
10 Years
Discussion Span
Last Post by Zork'nPalls
0

Long post, I know, but I just discovered:
Likewise, for the chararray-to-int method:
(it doesn't work properly any other way. Try 2147483647 as the value.)

public static int ToInt (byte[] data) {
	if (data == null) return 0x0;
	if (data.length != 4) return 0x0;
	return (
		(0xff & data[0])        |
		(0xff & data[1]) << 8   |
		(0xff & data[2]) << 16  |
		data[3] << 24
	);
}
0

Here's conversion methods for short, low byte given first in array.

public static byte[] toBytes(short s)
    {
        return new byte[]{(byte)(s & 0x00FF),(byte)((s & 0xFF00)>>8)};
    }
    
    public static short toShort(byte[] b)
    {
        return (short)(b[1]<<8 | b[0]);
    }
0

why not just log them as they are and use the methods in the wrapper classes to convert them back into primitive numbers?

0

why not just log them as they are and use the methods in the wrapper classes to convert them back into primitive numbers?

BECAUSE, that's not fun.
I "play" with Java to learn.
I know there's an easy way around everything, and if this were my job, I'd probably take the easy way. I, however, like to learn, and I like to know how things work. I want to convert the primitives to byte arrays, and I've done so. I just didn't understand *exactly* where my problems arise.

:cool:

Anyway, I found my problem just moments ago. Performing shift operations on anything converts it to an integer. The only remaining issue I was having was with char-array-to-long conversion, and it was because I wasn't converting certain things to long before working with them.. See the before and after, below. Maybe others can learn from this:

// BEFORE (Does Not Work for negatives and large longs)
public static long ToLong (byte[] data) {
	if (data == null) return 0x0;
	if (data.length != 8) return 0x0;
	return (long) ( // TODO: issues.
		(0xff & data[0])        |
		(0xff & data[1]) << 8   |
		(0xff & data[2]) << 16  |
		(0xff & data[3]) << 24  |
		(0xff & data[4]) << 32  |
		(0xff & data[5]) << 40  |
		(0xff & data[6]) << 48  |
		(0xff & data[7]) << 56
	);
}

// AFTER (Works for all longs)
public static long ToLong (byte[] data) {
	if (data == null) return 0x0;
	if (data.length != 8) return 0x0;
	return (long) ( // TODO: issues.
		(0xff & data[0])        |
		(0xff & data[1]) << 8   |
		(0xff & data[2]) << 16  |
		(0xff & data[3]) << 24  |
		(long)(0xff & data[4]) << 32  |
		(long)(0xff & data[5]) << 40  |
		(long)(0xff & data[6]) << 48  |
		(long)(0xff & data[7]) << 56
	);
}

:p There ya go! Conversions. I've learned something.

0

I think you need one more long cast in the toLong on the << 24 line. Here are all the functions that I put together for writing and reading including float and double. One thing I just noticed is that you have to be careful to write the correct type. Meaning, if you write an int and try to read a float, it doesn't work. so, be sure to write 1f rather than 1 for example.

public static void write(byte[] bytes, boolean b, int pos){
		bytes[pos] = (byte) (b ? 1 : 0);
	}
	
	public static void write(byte[] bytes, short s, int pos){		
		bytes[pos] = (byte)( (s >>> 8) & 0xFF );
		bytes[pos+1] = (byte)( (s >>> 0) & 0xFF);
	}
	
	public static void write(byte[] bytes, int i, int pos){		
		bytes[pos] = (byte)( (i >>> 24) & 0xFF );
		bytes[pos+1] = (byte)( (i >>> 16) & 0xFF);
		bytes[pos+2] = (byte)( (i >>> 8) & 0xFF);
		bytes[pos+3] = (byte)( (i >>> 0) & 0xFF);
	}
	
	public static void write(byte[] bytes, long l, int pos){		
		bytes[pos] = (byte)( (l >>> 56) & 0xFF );
		bytes[pos+1] = (byte)( (l >>> 48) & 0xFF);
		bytes[pos+2] = (byte)( (l >>> 40) & 0xFF);
		bytes[pos+3] = (byte)( (l >>> 32) & 0xFF);
		bytes[pos+4] = (byte)( (l >>> 24) & 0xFF);
		bytes[pos+5] = (byte)( (l >>> 16) & 0xFF);
		bytes[pos+6] = (byte)( (l >>> 8) & 0xFF);
		bytes[pos+7] = (byte)( (l >>> 0) & 0xFF);
	}
	
	public static void write(byte[] bytes, float f, int pos){
		write(bytes, Float.floatToIntBits(f), pos);
	}
	
	public static void write(byte[] bytes, double d, int pos){
		write(bytes, Double.doubleToLongBits(d), pos);
	}
	
	public static boolean readBoolean(byte[] bytes, int pos){
		return bytes[pos] == 1;
	}
		
	public static short readShort(byte[] bytes, int pos){		
		return (short)( ( (bytes[pos] << 8) ) | ( (bytes[pos+1] & 0xff) ) );
	}
	
	public static int readInt(byte[] bytes, int pos){
		return (int) (
			(0xff & bytes[pos + 3]) |
			(0xff & bytes[pos + 2]) << 8 |
			(0xff & bytes[pos + 1]) << 16 |
			(bytes[pos]) << 24			
		);
	}
	
	public static long readLong(byte[] bytes, int pos){
		return (long) (			
			(0xff & bytes[pos + 7]) |
			(0xff & bytes[pos + 6]) << 8 |
			(0xff & bytes[pos + 5]) << 16 |
			(long)(0xff & bytes[pos + 4]) << 24 |
			(long)(0xff & bytes[pos + 3]) << 32 |
			(long)(0xff & bytes[pos + 2]) << 40 |
			(long)(0xff & bytes[pos + 1]) << 48 |
			(long)(0xff & bytes[pos]) << 56
		);
	}
	
	public static float readFloat(byte[] bytes, int pos){
		return Float.intBitsToFloat( readInt(bytes, pos) );
	}
	
	public static double readDouble(byte[] bytes, int pos){
		return Double.longBitsToDouble( readLong(bytes, pos) );
	}
0

This thread appears to be created for the purposes of "playing around with an idea". I found it useful for my thesis so figured I'd post the implementation that I'm using to potentially save people time, and point out a small bug in the implementation. I imagine it will be more useful over the next 17 months than your criticism.

0

Hi ekirkco,

Can I just ask why you use a signed shift in your write methods? I'm just wondering because I saw this in another example on another forum but it wasn't explained and I had trouble when sending data to another computer. I ended up using an unsigned shift and it worked, but I don't know why...

0

The bitwise functions only operate on integers. When you wrote

    data[0]        |
    data[1] << 8

it didn't work as you thought when data contained {-128, 0}

-128 as a byte is 10000000
-128 as an int is 11111111111111111111111110000000 (25 1s, 7 0s)

the int is what is being used in the calculation, thus your data is all screwed up

thats why you use the "& 0xff" it condenses the 111...110000000 to what you originally wanted

in case you're confused, the leftmost bit is the sign bit

1 for negative numbers
0 for positive numbers

But its more confusing then just that, here is the rule for switching signs

positive to negative: switch the digits and add 1
negative to positive: subtract 1 then switch the digits

also there's a rule when moving from a smaller type to a larger type

just keep the original binary and fill the open spots on the left with the leftmost digit

Edited by mike_2000_17: Fixed formatting

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.