Quickest Way to Convert a Base 10 Number to Any Base in .Net

Quickest way to convert a base 10 number to any base in .NET?

Convert.ToString can be used to convert a number to its equivalent string representation in a specified base.

Example:

string binary = Convert.ToString(5, 2); // convert 5 to its binary representation
Console.WriteLine(binary); // prints 101

However, as pointed out by the comments, Convert.ToString only supports the following limited - but typically sufficient - set of bases: 2, 8, 10, or 16.

Update (to meet the requirement to convert to any base):

I'm not aware of any method in the BCL which is capable to convert numbers to any base so you would have to write your own small utility function. A simple sample would look like that (note that this surely can be made faster by replacing the string concatenation):

class Program
{
static void Main(string[] args)
{
// convert to binary
string binary = IntToString(42, new char[] { '0', '1' });

// convert to hexadecimal
string hex = IntToString(42,
new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'});

// convert to hexavigesimal (base 26, A-Z)
string hexavigesimal = IntToString(42,
Enumerable.Range('A', 26).Select(x => (char)x).ToArray());

// convert to sexagesimal
string xx = IntToString(42,
new char[] { '0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x'});
}

public static string IntToString(int value, char[] baseChars)
{
string result = string.Empty;
int targetBase = baseChars.Length;

do
{
result = baseChars[value % targetBase] + result;
value = value / targetBase;
}
while (value > 0);

return result;
}

/// <summary>
/// An optimized method using an array as buffer instead of
/// string concatenation. This is faster for return values having
/// a length > 1.
/// </summary>
public static string IntToStringFast(int value, char[] baseChars)
{
// 32 is the worst cast buffer size for base 2 and int.MaxValue
int i = 32;
char[] buffer = new char[i];
int targetBase= baseChars.Length;

do
{
buffer[--i] = baseChars[value % targetBase];
value = value / targetBase;
}
while (value > 0);

char[] result = new char[32 - i];
Array.Copy(buffer, i, result, 0, 32 - i);

return new string(result);
}
}

Update 2 (Performance Improvement)

Using an array buffer instead of string concatenation to build the result string gives a performance improvement especially on large number (see method IntToStringFast). In the best case (i.e. the longest possible input) this method is roughly three times faster. However, for 1-digit numbers (i.e. 1-digit in the target base), IntToString will be faster.

How to convert a base 10-number to 3-base in net (Special case)

Converting between systems is basic programming task and logic doesn't differ from other systems (such as hexadecimal or binary). Please, find below code:

//here you choose what number should be used to convert, you wanted 3, so I assigned this value here
int systemNumber = 3;
//pick number to convert (you can feed text box value here)
int numberToParse = 5;
// Note below
numberToParse++;
string convertedNumber = "";
List<char> letters = new List<char>{ 'A', 'B', 'C' };
//basic algorithm for converting numbers between systems
while(numberToParse > 0)
{
// Note below
numberToParse--;
convertedNumber = letters[numberToParse % systemNumber] + convertedNumber;
//append corresponding letter to our "number"
numberToParse = (int)Math.Floor((decimal)numberToParse / systemNumber);
}
//show converted number
MessageBox.Show(convertedNumber);

NOTE: I didn't read carefully at first and got it wrong. I added to previous solution two lines marked with "Note below": incrementation and decrementation of parsed number. Decrementation enables A (which is zero, thus omitted at the beginning of numbers) to be treated as relevent leading digit. But this way, numbers that can be converted are shifted and begin with 1. To compensate that, we need to increment our number at the beginning.

Additionaly, if you want to use other systems like that, you have to expand list with letter. Now we have A, B and C, because you wanted system based on 3. In fact, you can always use full alphabet:

List<char> letters = new List<char> {'A','B','C', 'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};

and only change systemNumber.

Converting a String or base10 to a base 2 in VB

Use the Convert.ToString method and specify the base as 2. This will convert an Integer value into a String in the specified base

Dim result = Convert.ToString(Integer.Parse(prVal), 2)

As @Dan pointed out if you want to force this to be width 8 use the PadLeft method

result = result.PadLeft(8, "0"c)

C# base converter

  1. For me, yes. the snippet in C# (as it is) should return C1, instead of 1C. You will need to reverse the string result before returning it. (or use instead something like result = string.Concat(alphabet[index].toString()); when creating the result string)

  2. That's correct. It also works in all the other bases, i.e. if we take your example (28), you'll have :

28 = 2 * 10^1 + 8 * 10^0 (base 10)

28 = 1 * 16^1 + 12 * 16^0 (base 16) = 1C

28 = 3 * 8^1 + 2 * 8^0 (base 8) = 32

etc, etc.

How To Do Direct Conversion From One Number Base To A New Number Base

It is pretty heavy topic. The steps do exist. You can do conversion between any two number systems. But you will be doing arithmetic calculation in a different number base. That itself is pretty hard to get your head around it.

I can quote the general concept behind direct base conversion from a W3 Spot article:

  1. Divide the number by the value of other base.

  2. Get the remainder. That is the least significant digit.

  3. Divide the quotient with the value of other base.

  4. Add the remainder as next least significant digit.

We need to keep doing steps 3 & 4 repeatedly till quotient becomes
zero.

But that's not all. There are subtle nuances when you convert from lower to higher base than the opposite way. Let's say, you are doing base-3 to base-6 conversion. You will have to do some arithmetic operation on the base-3 number. And all the calculation will be done in base-3 number system. How do we convert to base-6 number then? base-3 system doesn't have 3, 4 & 5 digits that are valid in base-6 system. You need to have a mapping first between base-3 digits & base-6 digits.

Also doing division in non-decimal number system is not easy. If you do it using pen & paper, you should create multiplication table in that number system.

All these things are not easy. That's why we convert to decimal system first. Anyways just go through the article I mentioned above. It explains the steps in details with examples for both lower to higher base & the opposite.

How to convert base 10 negative number to base 8 conversion without using Convert.To() method?

You can always go the source code of the Convert class at source.dot.net here and follow ParseNumber's IntToString method:

public static string IntToString(int n, int radix, int width, char paddingChar, int flags)
{
Span<char> buffer = stackalloc char[66]; // Longest possible string length for an integer in binary notation with prefix

if (radix < MinRadix || radix > MaxRadix)
throw new ArgumentException(SR.Arg_InvalidBase, nameof(radix));

// If the number is negative, make it positive and remember the sign.
// If the number is MIN_VALUE, this will still be negative, so we'll have to
// special case this later.
bool isNegative = false;
uint l;
if (n < 0)
{
isNegative = true;
(...)

.NET Conversion of very large numbers to different number base

Solution by Andrew Jonkers :

//Convert number in string representation from base:from to base:to. 
//Return result as a string
public static String Convert(int from, int to, String s)
{
//Return error if input is empty
if (String.IsNullOrEmpty(s))
{
return ("Error: Nothing in Input String");
}
//only allow uppercase input characters in string
s = s.ToUpper();

//only do base 2 to base 36 (digit represented by characters 0-Z)"
if (from < 2 || from > 36 || to < 2 || to > 36)
{ return ("Base requested outside range"); }

//convert string to an array of integer digits representing number in base:from
int il = s.Length;
int[] fs = new int[il];
int k = 0;
for (int i = s.Length - 1; i >= 0; i--)
{
if (s[i] >= '0' && s[i] <= '9') { fs[k++] = (int)(s[i] - '0'); }
else
{
if (s[i] >= 'A' && s[i] <= 'Z') { fs[k++] = 10 + (int)(s[i] - 'A'); }
else
{ return ("Error: Input string must only contain any of 0-9 or A-Z"); } //only allow 0-9 A-Z characters
}
}

//check the input for digits that exceed the allowable for base:from
foreach(int i in fs)
{
if (i >= from) { return ("Error: Not a valid number for this input base"); }
}

//find how many digits the output needs
int ol = il * (from / to+1);
int[] ts = new int[ol+10]; //assign accumulation array
int[] cums = new int[ol+10]; //assign the result array
ts[0] = 1; //initialize array with number 1

//evaluate the output
for (int i = 0; i < il; i++) //for each input digit
{
for (int j = 0; j < ol; j++) //add the input digit
// times (base:to from^i) to the output cumulator
{
cums[j] += ts[j] * fs[i];
int temp = cums[j];
int rem = 0;
int ip = j;
do // fix up any remainders in base:to
{
rem = temp / to;
cums[ip] = temp-rem*to; ip++;
cums[ip] += rem;
temp = cums[ip];
}
while (temp >=to);
}

//calculate the next power from^i) in base:to format
for (int j = 0; j < ol; j++)
{
ts[j] = ts[j] * from;
}
for(int j=0;j<ol;j++) //check for any remainders
{
int temp = ts[j];
int rem = 0;
int ip = j;
do //fix up any remainders
{
rem = temp / to;
ts[ip] = temp - rem * to; ip++;
ts[ip] += rem;
temp = ts[ip];
}
while (temp >= to);
}
}

//convert the output to string format (digits 0,to-1 converted to 0-Z characters)
String sout = String.Empty; //initialize output string
bool first = false; //leading zero flag
for (int i = ol ; i >= 0; i--)
{
if (cums[i] != 0) { first = true; }
if (!first) { continue; }
if (cums[i] < 10) { sout += (char)(cums[i] + '0'); }
else { sout += (char)(cums[i] + 'A'-10); }
}
if (String.IsNullOrEmpty(sout)) { return "0"; } //input was zero, return 0
//return the converted string
return sout;
}

Convert string from Base2 to Base4

.NET does not support conversion to non-standard base, such as 4, so this will not work:

Dim base4number As String = Convert.ToString(base10number, 4)

From MSDN:

[...] base of the return value [...] must be 2, 8, 10, or 16.

But you can write your own conversion function, or take the existing one off the web:

Public Function IntToStringFast(value As Integer, baseChars As Char()) As String
Dim i As Integer = 32
Dim buffer(i - 1) As Char
Dim targetBase As Integer = baseChars.Length

Do
buffer(System.Threading.Interlocked.Decrement(i)) =
baseChars(value Mod targetBase)
value = value \ targetBase
Loop While value > 0

Dim result As Char() = New Char(32 - i - 1) {}
Array.Copy(buffer, i, result, 0, 32 - i)

Return New String(result)
End Function

Used this answer. Converted with developer fusion from C# + minor adjustments. Example:

Dim base2number As String = "11110" 'Decimal 30
Dim base10number As Integer = Convert.ToInt32(base2number, 2)
Dim base4number As String = IntToStringFast(base10number, "0123")
Console.WriteLine(base4number) 'outputs 132

Notice that you don't need base 2 there as an intermediate value, you can convert directly from base 10. If in doubt, whether it worked correctly or not, here is a useful resource:

  • Number base converter

base_convert in .NET

Here's some code that'll convert an integer to an arbitrary base up to 36, and convert a string representation of a base x value to an integer (given the base):

class Program {
static void Main(string[] args) {
int b10 = 123;
int targetBase = 5;

string converted = ConvertToBase(b10, targetBase);
int convertedBack = ConvertFromBase(converted, targetBase);

string base3 = "212210";
string base7 = ConvertFromBaseToBase(base3, 3, 7);

Console.WriteLine(converted);
Console.WriteLine(convertedBack);
Console.WriteLine(base7);
Console.ReadLine();
}

private const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

private static string ConvertToBase(int b10, int targetBase) {
if (targetBase < 2) throw new ArgumentException("Target base must be greater than 2.", "targetBase");
if (targetBase > 36) throw new ArgumentException("Target base must be less than 36.", "targetBase");

if (targetBase == 10) return b10.ToString();

StringBuilder result = new StringBuilder();

while (b10 >= targetBase) {
int mod = b10 % targetBase;
result.Append(chars[mod]);
b10 = b10 / targetBase;
}

result.Append(chars[b10]);

return Reverse(result.ToString());
}

private static int ConvertFromBase(string bx, int fromBase) {
if (fromBase < 2) throw new ArgumentException("Base must be greater than 2.", "fromBase");
if (fromBase > 36) throw new ArgumentException("Base must be less than 36.", "fromBase");

if (fromBase == 10) return int.Parse(bx);

bx = Reverse(bx);
int acc = 0;

for (int i = 0; i < bx.Length; i++) {
int charValue = chars.IndexOf(bx[i]);
acc += (int)Math.Pow(fromBase, i) * charValue;
}

return acc;
}

public static string ConvertFromBaseToBase(string bx, int fromBase, int toBase) {
int b10 = ConvertFromBase(bx, fromBase);
return ConvertToBase(b10, toBase);
}

public static string Reverse(string s) {
char[] charArray = new char[s.Length];
int len = s.Length - 1;
for (int i = 0; i <= len; i++)
charArray[i] = s[len - i];
return new string(charArray);
}
}

If you're unconcerned with displaying these values, you can use extended characters in your chars set - if you stick to plain ascii, you can theoretically have base256 values. Going beyond that I would recommend not using chars, but instead using some other uniquely-identifiable value - though I don't much see the value.



Related Topics



Leave a reply



Submit