hex conversion

M

mcnewsxp

can someone help me convert this VB code so it will work? i've made
the changes and it compiles and runs, but this line always makes the
dremainder = 0 - dRemainder = dValue - (byBase * Int((dValue /
byBase))).

Public Function ConvertDecToBaseN(ByVal dValue As Double, Optional
ByVal byBase As Byte = 36) As String

Const BASENUMBERS As String =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim dRemainder As Double
Dim sResult As String

On Error GoTo ErrorHandler

sResult = ""
If (byBase < 2) Or (byBase > 36) Then GoTo done

dValue = Abs(dValue)
Do
dRemainder = dValue - (byBase * Int((dValue / byBase)))
sResult = Mid(BASENUMBERS, dRemainder + 1, 1) & sResult
dValue = Int(dValue / byBase)
Loop While (dValue > 0)

done:
ConvertDecToBaseN = pad(sResult, 0, 8)
Exit Function

ErrorHandler:
'Err.Raise Err.Number, "ConvertDecToBaseN", Err.Description
MsgBox "Error in Module1.ConvertDecToBaseN", Err.Number,
Err.Description
End Function

here's my conversion attempt:

internal static string ConvertDecToBaseN(double dValue, byte? byBase)
{
const string BASENUMBERS =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
double dRemainder;
string sResult;

try
{
if (!byBase.HasValue)
{ byBase = 36; }

sResult = "";
if ((byBase < 2) || (byBase > 36))
{ }
else
{
dValue = Math.Abs(dValue);
do
{
dRemainder = dValue - ((double)byBase *
((dValue / (double)byBase)));
sResult = BASENUMBERS.Substring(Convert.ToInt32
(dRemainder) + 1, 1) + sResult;
dValue = Convert.ToInt32(dValue / byBase);
} while (dValue > 0);

}
return (sResult.PadLeft(8, '0'));
}
catch (Exception err)
{
string strTmp = "";
strTmp = strTmp + "\n Freezer Inventory Error # " +
(err.ToString());
strTmp = strTmp + "\nError in
Module1.ConvertDecToBaseN";
MessageBox.Show(strTmp);
return ("");
}
}
 
M

mcnewsxp

can someone help me convert this VB code so it will work? i've made
the changes and it compiles and runs, but this line always makes the
dremainder = 0 - dRemainder = dValue - (byBase * Int((dValue /
byBase))).

The main problem is that you failed to account for the "Int()" part of
that expression when you converted to C#.  You should be truncating the
result of "dValue / byBase", either by casting or calling Math.Truncate()..

You also have an off-by-one bug, in that C# arrays are always 0-based, but
your code is written as if "BASENUMBERS" is 1-based (as the default for
VB.NET).

As far as the truncation goes, IMHO you would be better off just
performing the entire operation with integer arithmetic anyway:

      string ConvertDecToBaseN(double dValue, int byBase)
      {
          string BASENUMBERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
          string sResult = "";

          if (byBase >= 2 && byBase <= 36)
          {
              int i = (int)Math.Abs(dValue);

              while (i > 0)
              {
                  sResult = BASENUMBERS[i % byBase] +sResult;
                  i /= byBase;
              }
          }

          return sResult.PadLeft(8, '0');
      }

Note that one remaining issue that exists with both the VB.NET and the C#
versions is that it's inefficient to repeatedly concatenate a string in a
loop like that.  Assuming this method isn't a bottleneck in your code,
it's probably fine.  But you can make it more efficient by using a
pre-allocated StringBuilder instance for creating the result.

Somewhat related to that is the fact that a double can represent a number
that is much longer than 8 digits.  It's not clear from your question
whether this is a bug in the original implementation, or if you really
intend for the method to be able to emit a string longer than 8 digits
even though you only pad it to 8 digits.  But, if it's a bug and the
output should always have exactly some number of digits, you can write the
more-efficient version even more efficiently, by pre-initializing your
StringBuilder to a string of '0' characters the exact length the output
should be, and then work your way from the end of the string back as you
generate the individual digits.  When you're done with the conversion, the
remainder of the StringBuilder will already have the '0' digits you need
in the remaining positions, and you won't need to call String.PadLeft() at
all.

I'm also not a big fan of silently discarding erroneous input to the
method.  IMHO, the method really ought to just throw an exception if the
base is out of range, rather than just returning "00000000".

All of the above assumes that you really do need a method that can deal
with any arbitrary base from 2 to 36.  If base 10 and 16 are sufficient,
.NET already has string formatting options that will format those bases
for you exactly.

Finally, you'll note that the method I posted doesn't use a nullable type
for the base argument, nor is it a byte.  There's really no point in using
"byte" as the type; you don't really save anything, and the natural type
for the subsequent calculations is going to be "int" anyway.

As for the nullable type, IMHO that's not a great idiom for optional
arguments.  I prefer instead to provide a method overload:

      string ConvertDecToBaseN(double dValue)
      {
          return ConvertDecToBaseN(dValue, 36);
      }

Let the compiler do the work for you, rather than the run-time.

Of course, in C# 4.0, the language has actual optional arguments.  If you
use that version, then you can just make the argument optional as in
VB.NET.

Pete

thanks for a truly informative response!
 

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