Converting numbers between different bases is a common task in computer science. While .NET provides built-in functions for converting to bases 2, 8, 10, and 16, it lacks native support for arbitrary bases. This article explores various C# methods for converting base 10 numbers to any base, offering solutions for different performance needs and base character sets.
The core challenge lies in adapting the standard base conversion algorithm to work with any set of characters representing the digits of the target base. This requires a custom implementation that handles the modulo and division operations and maps the resulting remainders to the corresponding characters in the desired base.
This approach involves creating a function that repeatedly divides the input number by the target base, using the remainder to select the appropriate character from a predefined character set. The resulting characters are then concatenated to form the final representation.
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;
}
Example Usage:
string binary = IntToString(42, new char[] { '0', '1' }); // Convert to binary
string hex = IntToString(42, new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }); // Convert to hexadecimal
string hexavigesimal = IntToString(42, Enumerable.Range('A', 26).Select(x => (char)x).ToArray()); // Convert to hexavigesimal (A-Z)
Pros:
Cons:
To improve performance, especially for larger numbers, an array buffer can be used instead of string concatenation. This method pre-allocates a character array and fills it in reverse order, avoiding the overhead of repeated string allocations.
public static string IntToStringFast(int value, char[] baseChars)
{
int i = 32; // Worst-case buffer size for base 2 and int.MaxValue
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);
}
Pros:
Cons:
This particular implementation is inspired by a blog post and provides a streamlined approach. It avoids string operations during calculations, potentially offering speed advantages. However, it limits the base to a range between 2 and 36, using a predefined set of digits.
public static string DecimalToArbitrarySystem(long decimalNumber, int radix)
{
const int BitsInLong = 64;
const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (radix < 2 || radix > Digits.Length)
throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString());
if (decimalNumber == 0)
return "0";
int index = BitsInLong - 1;
long currentNumber = Math.Abs(decimalNumber);
char[] charArray = new char[BitsInLong];
while (currentNumber != 0)
{
int remainder = (int)(currentNumber % radix);
charArray[index--] = Digits[remainder];
currentNumber = currentNumber / radix;
}
string result = new String(charArray, index + 1, BitsInLong - index - 1);
if (decimalNumber < 0)
{
result = "-" + result;
}
return result;
}
Pros:
Cons:
For scenarios requiring both conversion from base 10 to an arbitrary base and back, this method provides a pair of functions optimized for speed. It uses a dictionary to quickly map characters to their corresponding values, enabling efficient conversion in both directions.
private static readonly char[] BaseChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
private static readonly Dictionary<char, int> CharValues = BaseChars
.Select((c, i) => new { Char = c, Index = i })
.ToDictionary(c => c.Char, c => c.Index);
public static string LongToBase(long value)
{
long targetBase = BaseChars.Length;
char[] buffer = new char[Math.Max((int)Math.Ceiling(Math.Log(value + 1, targetBase)), 1)];
var i = buffer.Length;
do
{
buffer[--i] = BaseChars[value % targetBase];
value = value / targetBase;
} while (value > 0);
return new string(buffer, i, buffer.Length - i);
}
public static long BaseToLong(string number)
{
char[] chrs = number.ToCharArray();
int m = chrs.Length - 1;
int n = BaseChars.Length, x;
long result = 0;
for (int i = 0; i < chrs.Length; i++)
{
x = CharValues[chrs[i]];
result += x * (long)Math.Pow(n, m--);
}
return result;
}
Pros:
Cons:
Choosing the right method for converting base 10 numbers to other bases in C# depends on the specific requirements of your application. For simple conversions or when dealing with small numbers, the string concatenation approach may suffice. For higher performance, especially with larger numbers, the array buffer method or the blog-inspired implementation are better choices. If you need efficient conversion in both directions, the dictionary-based method offers the best performance.