Efficiency of stuffing & reconstituting primitives in a byte[]

Q

Qu0ll

I am stuffing a byte[] with byte, short and int values and then
reconstituting them elsewhere. Everything works fine but I am concerned
that I am not doing it as efficiently as possible.

The code to stuff a short named x into the byte[] buffer (high byte first)
looks like this:

buffer[index++] = (byte)(((short)x & 0xFF00) >> 8);
buffer[index++] = (byte)( (short)x & 0x00FF);

The code to reconstitute the short looks like this:

byte a = buffer[index++];
byte b = buffer[index++];
short as = a;
short bs = b < 0 ? (short)((b & 0x7F) + 128) : b;
x = (short)((as << 8) | bs);

Is this the most efficient way of doing this? I find it annoying that bytes
are signed. I am also concerned that it may not work for all short values.

--
And loving it,

-Q
_________________________________________________
(e-mail address removed)
(Replace the "SixFour" with numbers to email me)
 
E

Eric Sosman

Qu0ll said:
I am stuffing a byte[] with byte, short and int values and then
reconstituting them elsewhere. Everything works fine but I am concerned
that I am not doing it as efficiently as possible.

The code to stuff a short named x into the byte[] buffer (high byte
first) looks like this:

buffer[index++] = (byte)(((short)x & 0xFF00) >> 8);
buffer[index++] = (byte)( (short)x & 0x00FF);

The (short) casts are unnecessary unless `x' is a float
or a double. Also, you can get rid of the masks and just
rely on the (byte) casts:

buffer[index++] = (byte)(x >> 8);
buffer[index++] = (byte)x;

.... but you'll probably need to do this to quite a large
number of values before you see a measurable speed change.
The code to reconstitute the short looks like this:

byte a = buffer[index++];
byte b = buffer[index++];
short as = a;
short bs = b < 0 ? (short)((b & 0x7F) + 128) : b;
x = (short)((as << 8) | bs);

You're working too hard. Try

short x = (short)(buffer[index++] << 8);
x += buffer[index++] & 0xFF;

You could even pack all of this into one statement like

short x = (short)((buffer[index++] << 8)
+ (buffer[index++] & 0xFF));

.... but this is cringe-inducing to old C programmers
like me. (Even though javac knows how to organize the
side-effects, there's no point in giving the maintenance
programmer a chance to make a "harmless" rearrangement.)
Is this the most efficient way of doing this?

Maybe, maybe not, and maybe the answer is different on
different systems. How much will you suffer if it turns
out to be only the second- or third-most efficient?
I find it annoying that
bytes are signed.

So do I. I also find it annoying that mosquitoes bite,
but I learn to get along anyhow.
I am also concerned that it may not work for all
short values.

As far as I can tell, both the originals and the rewrites
should work for all values. But since there are only 65536
short values, you could easily write a little test program
to pack and unpack all of them and report any discrepancies.
 
P

Patricia Shanahan

Eric said:
Qu0ll wrote: ....
byte a = buffer[index++];
byte b = buffer[index++];
short as = a;
short bs = b < 0 ? (short)((b & 0x7F) + 128) : b;
x = (short)((as << 8) | bs);

You're working too hard. Try

short x = (short)(buffer[index++] << 8);
x += buffer[index++] & 0xFF; ....
Is this the most efficient way of doing this?

Maybe, maybe not, and maybe the answer is different on
different systems. How much will you suffer if it turns
out to be only the second- or third-most efficient?

There is a risk that the conditional branch version will be slow on deep
pipeline processors for mixed sign data. Each conditional branch that is
not correctly predicted causes a pipeline flush, and subsequent delay
while the correct code works its way though the pipeline.

This seems to me to be a case where the simpler, cleaner code is also
likely to be the more efficient, if there is any difference.

Patricia
 
D

Daniel Pitts

Qu0ll said:
I am stuffing a byte[] with byte, short and int values and then
reconstituting them elsewhere. Everything works fine but I am concerned
that I am not doing it as efficiently as possible.

The code to stuff a short named x into the byte[] buffer (high byte
first) looks like this:

buffer[index++] = (byte)(((short)x & 0xFF00) >> 8);
buffer[index++] = (byte)( (short)x & 0x00FF);

The code to reconstitute the short looks like this:

byte a = buffer[index++];
byte b = buffer[index++];
short as = a;
short bs = b < 0 ? (short)((b & 0x7F) + 128) : b;
x = (short)((as << 8) | bs);

Is this the most efficient way of doing this? I find it annoying that
bytes are signed. I am also concerned that it may not work for all
short values.
Have you looked into using a ByteBuffer?
<http://java.sun.com/j2se/1.5.0/docs/api/java/nio/ByteBuffer.html>
It has putInt, putLong, putShort, putChar, putDouble, etc....

You can use ByteBuffer.wrap(bufferArray) too.


HTH.
 
Q

Qu0ll

Thank you Eric for your very useful reply. Comments inline...
The (short) casts are unnecessary unless `x' is a float
or a double. Also, you can get rid of the masks and just
rely on the (byte) casts:

buffer[index++] = (byte)(x >> 8);
buffer[index++] = (byte)x;

... but you'll probably need to do this to quite a large
number of values before you see a measurable speed change.

Yes, I see now the unnecessary nature of the (short) casts and masks. It's
much simpler and easier to maintain this way and makes the task of stuffing
int values easy too.
You're working too hard. Try

short x = (short)(buffer[index++] << 8);
x += buffer[index++] & 0xFF;

This will do nicely. I need to do some processing between accesses to the
buffer so this works better for me than the more concise solution you also
suggested.
Maybe, maybe not, and maybe the answer is different on
different systems. How much will you suffer if it turns
out to be only the second- or third-most efficient?

It doesn't really matter whether it's an order of magnitude more efficient
or not. What matters is that it's simpler and that I have learned something
in the process.
As far as I can tell, both the originals and the rewrites
should work for all values. But since there are only 65536
short values, you could easily write a little test program
to pack and unpack all of them and report any discrepancies.

While I haven't run this exact test, I have run the application with a vast
selection of values and it has proven to be 100% reliable.

Thanks again!

--
And loving it,

-Q
_________________________________________________
(e-mail address removed)
(Replace the "SixFour" with numbers to email me)
 
N

Nigel Wade

Qu0ll said:
I am stuffing a byte[] with byte, short and int values and then
reconstituting them elsewhere. Everything works fine but I am concerned
that I am not doing it as efficiently as possible.

The code to stuff a short named x into the byte[] buffer (high byte first)
looks like this:

buffer[index++] = (byte)(((short)x & 0xFF00) >> 8);
buffer[index++] = (byte)( (short)x & 0x00FF);

The code to reconstitute the short looks like this:

byte a = buffer[index++];
byte b = buffer[index++];
short as = a;
short bs = b < 0 ? (short)((b & 0x7F) + 128) : b;
x = (short)((as << 8) | bs);

Is this the most efficient way of doing this? I find it annoying that bytes
are signed. I am also concerned that it may not work for all short values.

Have you considered using ByteBuffer? It is designed to do exactly this kind of
thing. Whether it is more efficient is another matter entirely, but it ought to
be simpler and your intention should be more transparent.
 
Q

Qu0ll

Have you looked into using a ByteBuffer?
<http://java.sun.com/j2se/1.5.0/docs/api/java/nio/ByteBuffer.html>
It has putInt, putLong, putShort, putChar, putDouble, etc....

You can use ByteBuffer.wrap(bufferArray) too.

Yes, I see now that ByteBuffer does pretty much what I was trying to do but
I am going to stick with the original approach (and Eric's improvements)
because it works, it is as efficient as it can be and all this is happening
inside an applet where I am trying to limit the number of classes being
loaded.

But thanks for the suggestion (also to Nigel for suggesting same).

--
And loving it,

-Q
_________________________________________________
(e-mail address removed)
(Replace the "SixFour" with numbers to email me)
 
R

Roedy Green

I am stuffing a byte[] with byte, short and int values and then
reconstituting them elsewhere. Everything works fine but I am concerned
that I am not doing it as efficiently as possible.

You can use a DataOutputStream to a ByteArrayStream. Sun is going to
write pretty good code. You can also peek at how Sun does it by
looking up the code in src.zip or letting your IDE find it for you.

I have similar code in LEDataStream doing the same thing for little
endian binary data.

See http://mindprod.com/products.html#LEDATASTREAM
 
G

Greg R. Broderick

I am stuffing a byte[] with byte, short and int values and then
reconstituting them elsewhere. Everything works fine but I am concerned
that I am not doing it as efficiently as possible.

Efficiency is in the eyes of the beholder - the code you've written is very
efficient in terms of economy of memory usage, but fails to be efficient when
the code needs to be maintained, as it is relatively difficult to deduce the
purpose of stuffing these three values into one. This loss of efficiency may
end up costing you more in the long run - what happens when a junior coder is
tasked with adding a fourth value into the composed collection of values.

If your purpose is to return three values as one from a method call, then I
would recommend that you create a small private inner class that contains
each of the three individual values that you need to return as instance
fields, and that you return an object of this class instead of performing
these gymnastics.

Cheers!
GRB

--
---------------------------------------------------------------------
Greg R. Broderick (e-mail address removed)

A. Top posters.
Q. What is the most annoying thing on Usenet?
---------------------------------------------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top