bytes To Hex

  • Thread starter Thread starter Analizer1
  • Start date Start date
Peter said:
I wouldn't suggest using StringBuilder in this case anyway. You've got
a finite well-defined string length to deal with and I doubt there's a
significant performance difference between the two. Just appending
String instances eight times is probably fine, even though it does
result in a much larger number of data copies.
Well, I thought we were talking about the general case of turning an
arbitrary array of bytes into a string. Sure, if you're limited to eight
bytes exactly, then you don't need a loop to begin with. But then my point
also vanishes.
I disagree that there's anything wrong with using some sort of
formatting in a loop here.

The point is that String.Format() is expensive compared to other string
operations. In most cases, it's a cost you'll want to pay, because being
able to write

String.Format("There's {0} foozits out of {1} remaining with an average
processing time of {2} per item", remaining, total, averageTime);

is a lot more convenient and readable than doing the same with
concatenation. Especially when you combine this with locale-specific
formatting, precision modifiers and last but certainly not least localization.

And if you're doing *that* in a loop, then it's probably because it's
exactly what you need to do, and avoiding it won't buy you anything but
missed deadlines and angry customers.
Rules like "don't format strings in loops" just leads to
difficult-to-read code (C programmers notwithstanding :) ). It's not a
good rule, because there are so many good exceptions to it.
That's why I'd never suggest something like that as a general rule, it's
like saying "don't use useful things because they don't work for free", and
nothing is ever for free. And, sure, the usual caveats about "don't optimize
(yet)" apply. But a programmer should be able to understand and explain why
calling StringBuilder.AppendFormat() to repeatedly string two hex digits
together is a potentially inefficient solution, even if it's not a
bottleneck in practice (that is, it's not *too* inefficient so it doesn't
matter).

And this *particular* problem (assuming we're going back to the general case
of arbitrarily long arrays) happens to be better solved with BitConverter,
not only because it's faster, but because it absolves you from writing the
actual code! Reuse and less potential for errors, what's not to like? Hence
the "if it's obvious to avoid" clause.
 
Writing code that's comparatively difficult to understand like that is
Now here's where I'm slightly offended at the suggestion of producing
unreadable code. Most C programmers would agree that my version is a
paragon of readability. :-D

If we're gonna argue the point... any "real" C programmer would favor this
version:

static const string hexDigits = "0123456789abcdef";

int l = aBytes.Length;
char* from = aBytes + l;
l <<= 1;
char[] result = new char[l];
try {
for (;;) {
result[--l] = hexDigits[0x0F & *(--from)];
result[--l] = hexDigits[*from >> 4];
}
}
finally {
Console.WriteLine(result); // no need to make a string
// let someone who cares handle the exception
}

as a special bonus, due to the unorthodox method of leaving the loop, it can
be unrolled by any arbitrary factor without regard for whether the input
array length is a multiple of the unrolling factor

P.S. Using the digit one and lowercase L in the same statement is mandatory
 
i was able to read your sample code..
thanks again, and i agree about long loops.

if i have a long loop ..i tend to do as little stack pops as i can

tks
 
Analizer1 said:
probrably do between 100 and 200 thousand a day

Is that all? On my laptop - hardly a server class machine - I can
convert 16 bytes 200,000 times in about 1500ms using the code I posted.
(I haven't tested other code - it may well be faster.)

In other words, this is likely to account for less than 0.002% of the
time of the app.

Do you still think you need the "fastest and tightest conversion
possible"?
 
its not the number, hell it could be 3 million times a day...
our system..goes to sql, then domain , then back to the code to create this
hexstring....

Im just trying to get rid of some of the other hits...

it dont matter if its 1 call or 10 million calls...
i prefer the most efficient way....
Hence i asked for your advice

thanks
 
its not the number, hell it could be 3 million times a day...

Even if you called it 3 million times, that would only be 22 seconds out
of the entire day spent in that part of the code. Which brings the
proportional cost all the way up to a whopping 0.03% of the time of the
application.
our system..goes to sql, then domain , then back to the code to create
this
hexstring....

Im just trying to get rid of some of the other hits...

Which other hits? If you want to make your application faster, figure out
a way to avoid having to talk to the SQL server so often. That's likely
to reap genuine, useful benefits.
it dont matter if its 1 call or 10 million calls...
i prefer the most efficient way....
Hence i asked for your advice

And you got it. Which is to not waste time on optimizing this part of the
code. Make it easy to maintain, so that it doesn't cost a _human_ a lot
of time. Don't worry about the time the _computer_ spends on the code,
worry about the time the human does.

Even if you assume that you can eliminate 30 seconds a day by modifying
this part of the code, in an entire year you've only saved three hours of
computing time. Now compare that to the cost of a human trying to
maintain the code, taking into account the fact that a human costs a _lot_
more than a computer, for a given amount of time spent on a problem.

You're welcome.

Pete
 
Analizer1 said:
its not the number, hell it could be 3 million times a day...

Ooh, a shocking 15 seconds a day (if you only use a single core on a
laptop)...
our system..goes to sql, then domain , then back to the code to create this
hexstring....

And you really think *this* bit will be the bottleneck?
Im just trying to get rid of some of the other hits...

it dont matter if its 1 call or 10 million calls...

Yes, it really does. *If* this section of code ends up as a bottleneck,
*that's* the time to look at the efficiency of it.
i prefer the most efficient way....
Hence i asked for your advice

My advice is to code for the most *readable* solution rather than the
fastest. Then you can analyse the performance of the whole system, work
out the bottlenecks, and micro-optimise them. You can do that
confidently and easily, because all the code will be reasonably easy to
understand - because you won't have optimised inappropriately.
 
Analizer1 said:
it dont matter if its 1 call or 10 million calls...
i prefer the most efficient way....

If you are doing this on your own time because you find
it interesting as an intellectual exercise, then just
proceed.

Just don't do it on company time. Efficiency in company
world are measured in dollars. Spending many hours creating
some special fast code that will also require maintenance
programmers to spend extra hours understanding the
code to save 100 dollars worth of CPU power is bad business.

Arne
 
Analizer1 said:
I Want The Fastest and Tightest Conversion Possible

Try and run the code below for some ideas.

Arne

==============================================

using System;
using System.Text;

namespace E
{
public class HexFun
{
private static char[] HEXDIGITS = "0123456789ABCDEF".ToCharArray();
public delegate string ToHex(byte[] b);
public static string ToHex1(byte[] b)
{
return BitConverter.ToString(b).Replace("-", "");
}
public static string ToHex2(byte[] b)
{
StringBuilder sb = new StringBuilder(2 * b.Length);
for(int i = 0; i < b.Length; i++)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
public static string ToHex3(byte[] b)
{
StringBuilder sb = new StringBuilder(2 * b.Length);
for(int i = 0; i < b.Length; i++)
{
sb.Append(HEXDIGITS[b / 16]);
sb.Append(HEXDIGITS[b % 16]);
}
return sb.ToString();
}
public static string ToHex4(byte[] b)
{
StringBuilder sb = new StringBuilder(2 * b.Length);
for(int i = 0; i < b.Length; i++)
{
sb.Append(HEXDIGITS[b >> 4]);
sb.Append(HEXDIGITS[b & 0x0F]);
}
return sb.ToString();
}
public static string ToHex5(byte[] b)
{
char[] res = new char[2 * b.Length];
for(int i = 0; i < b.Length; i++)
{
res[2 * i] = HEXDIGITS[b >> 4];
res[2 * i + 1] = HEXDIGITS[b & 0x0F];
}
return new string(res);
}
private static char[] UH;
private static char[] LH;
static HexFun()
{
UH = new char[256];
LH = new char[256];
for(int i = 0; i < 256; i++)
{
UH = HEXDIGITS[i / 16];
LH = HEXDIGITS[i % 16];
}
}
public static string ToHex6(byte[] b)
{
char[] res = new char[2 * b.Length];
for(int i = 0; i < b.Length; i++)
{
res[2 * i] = UH[b];
res[2 * i + 1] = LH[b];
}
return new string(res);
}
public static void Test(byte[] b, int n, ToHex th)
{
DateTime dt1 = DateTime.Now;
for(int i = 0; i < n; i++)
{
th(b);
}
DateTime dt2 = DateTime.Now;
Console.WriteLine("{0:f4}", (dt2 - dt1).TotalSeconds);
}
private const int NBYT = 8;
private const int NREP = 4000000;
private static Random rng = new Random();
public static void Main(string[] args)
{
byte[] tst = { 1, 2, 3, 4, 255 };
Console.WriteLine(ToHex1(tst));
Console.WriteLine(ToHex2(tst));
Console.WriteLine(ToHex3(tst));
Console.WriteLine(ToHex4(tst));
Console.WriteLine(ToHex5(tst));
Console.WriteLine(ToHex6(tst));
byte[] b = new byte[NBYT];
rng.NextBytes(b);
Test(b, NREP, ToHex1);
Test(b, NREP, ToHex2);
Test(b, NREP, ToHex3);
Test(b, NREP, ToHex4);
Test(b, NREP, ToHex5);
Test(b, NREP, ToHex6);
Console.ReadKey();
}
}
}
 
Back
Top