Representing a ulong as An Array of Bytes

G

Guest

I need to store a uint in an array of bytes. Doing it old fashioned
style works:

byte[] b=new byte[8];
ulong ul = 1;
for(int j=0; j<8; j++)
{
--- obviously I could (and did) optimize the code inside the loop
--- I just wanted to keep my example simple
b[7 - j] = (byte)((ul & bmask) >> j*8);
bmask = bmask << 8;
}

It gives me exactly what I need:
b[0] = 0;
b[1] = 0;
(snip)
b[7] = 1;

I was trying to use MemoryStream and BinaryWriter and see how fast it
performs:

MemoryStream ms = new MemoryStream(16);
BinaryWriter br = new BinaryWriter(ms);

for(ulong i=1; i<3; i++)
{
br.Write(i);
}
byte[] b = ms.ToArray();

Unfortunately the order of bytes is not what I want:
b[0] = 1;
b[1] = 0;
b[2] = 0;
(snip)
b[7] = 0;

Is there any way to use canned classes like MemoryStream and
BinaryWriter and get the results that I got from my first snippet? The
reason I am asking is simple: canned classes might perform faster than
my homemade solution.
 
G

Guest

Thank you Greg. I am comparing different ways to send a large array of
unsigned longs to SQL Server 2000. The solution needs to be very
performant. Among other alternatives, I am sending to the database an
image, as follows:

SqlCommand a = new SqlCommand("ImageTest", conn);
a.CommandType = System.Data.CommandType.StoredProcedure;
a.Parameters.Add(new SqlParameter("@image",
System.Data.SqlDbType.Image,2147483647));
-- b is an array of bytes
a.Parameters[0].Value = b;

My understanding is that BitConverter will create a new array of bytes
for every unsigned long, and I think that would be hard on the garbage
collector. My understanding is that most likely I will not notice that
in a short test on my local PC, but eventually in the production that
would cause a slowdown. So I estimate that in my situation it is better
to swap then bytes manually so that there are only 2 new objects as
opposed to 10001:

MemoryStream ms = new MemoryStream(80000);
BinaryWriter br = new BinaryWriter(ms);
for(ulong i=1; i<10001; i++)
{
br.Write(i);
}
byte[] b = ms.ToArray();
byte[] b1 = new byte[80000];
--- swap the bytes manually
for(k=0; k<80000; k+=8)
{
for(j=0; j<8; j++)
{
b1[k+7-j] = b[k+j];
}
}

Please correct me if I am wrong.
 
G

Greg Young

Or you could just use a BinaryWriter and a memory stream .. the binary
writer actually does this in a more effiicient way than you do..

reflector'ed source of write method.

public virtual void Write(long value)
{
this._buffer[0] = (byte) value;
this._buffer[1] = (byte) (value >> 8);
this._buffer[2] = (byte) (value >> 0x10);
this._buffer[3] = (byte) (value >> 0x18);
this._buffer[4] = (byte) (value >> 0x20);
this._buffer[5] = (byte) (value >> 40);
this._buffer[6] = (byte) (value >> 0x30);
this._buffer[7] = (byte) (value >> 0x38);
this.OutStream.Write(this._buffer, 0, 8);
}


Cheers,

Greg Young
MVP - C#
http://codebetter.com/blogs/gregyoung
 
J

Jon Skeet [C# MVP]

I need to store a uint in an array of bytes.

See http://www.pobox.com/~skeet/csharp/miscutil

It provides:
1) A BinaryWriter that lets you specify the endianness
2) A BitConverter that lets you specify the endianness *and convert
into an existing array*

They may well not be faster than your original solution, but I strongly
suspect that talking to SQL server is going to be a bottleneck long
before this is. What are your performance requirements for this section
of the code, and how do current solutions compare with it?
 
G

Guest

Or you could just use a BinaryWriter and a memory stream .. the binary
writer actually does this in a more effiicient way than you do..

reflector'ed source of write method.

public virtual void Write(long value)
{
this._buffer[0] = (byte) value;
this._buffer[1] = (byte) (value >> 8);
this._buffer[2] = (byte) (value >> 0x10);
this._buffer[3] = (byte) (value >> 0x18);
this._buffer[4] = (byte) (value >> 0x20);
this._buffer[5] = (byte) (value >> 40);
this._buffer[6] = (byte) (value >> 0x30);
this._buffer[7] = (byte) (value >> 0x38);
this.OutStream.Write(this._buffer, 0, 8);
}

Thanks Greg, this code snippet really helped. In fact, I don't see any
advantage of using a memory stream. It's so simple:

static byte[] UlongsToBytes(ulong[] ulongs)
{
int ifrom = ulongs.GetLowerBound(0);
int ito = ulongs.GetUpperBound(0);
int l = (ito - ifrom + 1)*8;
byte[] ret = new byte[l];
int retind = 0;
for(int i=ifrom; i<ito; i++)
{
ulong v = ulongs;
ret[retind++] = (byte) (v >> 0x38);
ret[retind++] = (byte) (v >> 0x30);
ret[retind++] = (byte) (v >> 40);
ret[retind++] = (byte) (v >> 0x20);
ret[retind++] = (byte) (v >> 0x18);
ret[retind++] = (byte) (v >> 0x10);
ret[retind++] = (byte) (v >> 8);
ret[retind++] = (byte) v;
}

return ret;
}

Am I missing something? Why should I use a memory stream?
 
G

Guest

See http://www.pobox.com/~skeet/csharp/miscutil

It provides:
1) A BinaryWriter that lets you specify the endianness
2) A BitConverter that lets you specify the endianness *and convert
into an existing array*

They may well not be faster than your original solution, but I strongly
suspect that talking to SQL server is going to be a bottleneck long
before this is. What are your performance requirements for this section
of the code, and how do current solutions compare with it?

Thanks Jon, reading the sources was very interesting. The performance
requirements are simple: it must work faster than the competitors'
solutions.
 
G

Greg Young

Well ...

1) the memory stream automatically will size itself ..
2) you can just use a BinaryWriter ... that code is reflector'ed from the
BinaryWriter class .. Why write it yourself?

Cheers,

Greg Young
MVP - C#
http://codebetter.com/blogs/gregyoung

Or you could just use a BinaryWriter and a memory stream .. the binary
writer actually does this in a more effiicient way than you do..

reflector'ed source of write method.

public virtual void Write(long value)
{
this._buffer[0] = (byte) value;
this._buffer[1] = (byte) (value >> 8);
this._buffer[2] = (byte) (value >> 0x10);
this._buffer[3] = (byte) (value >> 0x18);
this._buffer[4] = (byte) (value >> 0x20);
this._buffer[5] = (byte) (value >> 40);
this._buffer[6] = (byte) (value >> 0x30);
this._buffer[7] = (byte) (value >> 0x38);
this.OutStream.Write(this._buffer, 0, 8);
}

Thanks Greg, this code snippet really helped. In fact, I don't see any
advantage of using a memory stream. It's so simple:

static byte[] UlongsToBytes(ulong[] ulongs)
{
int ifrom = ulongs.GetLowerBound(0);
int ito = ulongs.GetUpperBound(0);
int l = (ito - ifrom + 1)*8;
byte[] ret = new byte[l];
int retind = 0;
for(int i=ifrom; i<ito; i++)
{
ulong v = ulongs;
ret[retind++] = (byte) (v >> 0x38);
ret[retind++] = (byte) (v >> 0x30);
ret[retind++] = (byte) (v >> 40);
ret[retind++] = (byte) (v >> 0x20);
ret[retind++] = (byte) (v >> 0x18);
ret[retind++] = (byte) (v >> 0x10);
ret[retind++] = (byte) (v >> 8);
ret[retind++] = (byte) v;
}

return ret;
}

Am I missing something? Why should I use a memory stream?
 
J

Jon Skeet [C# MVP]

Thanks Jon, reading the sources was very interesting. The performance
requirements are simple: it must work faster than the competitors'
solutions.

Presumably that's an *overall* requirement though, not a requirement of
this particular piece of the code. Have you measured how much of the
time is spent converting ulongs to arrays of bytes?
 
J

Jon Skeet [C# MVP]

Greg Young said:
1) the memory stream automatically will size itself ..
2) you can just use a BinaryWriter ... that code is reflector'ed from the
BinaryWriter class .. Why write it yourself?

Check the differences between the code you posted and the version the
OP just posted - the endianness is different.
 
G

Guest

Presumably that's an *overall* requirement though, not a requirement of
this particular piece of the code. Have you measured how much of the
time is spent converting ulongs to arrays of bytes?
Jon,

Your point is taken. You are correct - the time on the client side is
negligible either way.
 

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

Top