
I wanted to encode a number in Base 36. A simple enough task, but as these things sometimes do, this took me down the rabbit hole of wanting to create a generic routine. I needed a set of methods, one that would take an integer and convert it to an arbitrary base and another to convert it back to a Base 10 number. There are a bunch of examples floating around the web but I wanted to create my own (combining some of the best elements from the code I found). It's a relatively easy problem to solve but along the way I found some interesting tricks to speed up the process.
So here is my C# take on this old problem:
// Chars to use in Base conversion private const string BASE_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ; /// <summary> /// Convert a base 10 number to a different base. /// </summary> /// <param name="number">Number to convert</param> /// <param name="radix">Base to convert the number into (2-62)</param> /// <returns>String</returns> public static string NumberToBase( long number, int radix) { if (number == 0) return "0" ; if (radix < 2 || radix > BASE_DIGITS.Length) throw new ArgumentOutOfRangeException( "radix" , radix, "The Radix/Base must be between 2 and " + BASE_DIGITS.Length); var baseChars = BASE_DIGITS.ToCharArray(); var charStack = new Stack< char >(); var num = Math.Abs(number); while (num != 0) { charStack.Push(baseChars[num % radix]); num /= radix; } var result = new string (charStack.ToArray()); return number < 0 ? "-" + result : result; } /// <summary> /// Convert a string in a different base to a base 10 number /// </summary> /// <param name="number">Number to convert</param> /// <param name="radix">Base to convert from</param> /// <returns>Int64</returns> public static long NumberFromBase( string number, int radix) { if (radix < 2 || radix > BASE_DIGITS.Length) throw new ArgumentOutOfRangeException( "radix" , radix, "The Radix/Base must be between 2 and " + BASE_DIGITS.Length); long result = 0; long multiplier = 1; for (var i = number.Length - 1; i >= 0; i--) { var c = number[i]; // This is the negative sign symbol if (i == 0 && c == '-' ) { result = -result; break ; } result += BASE_DIGITS.IndexOf(c) * multiplier; multiplier *= radix; } return result; } |
I used LINQPad to create a quick program to test it out.
void Main() { Random r = new Random(); for ( int i = -1000; i < 1000000; i++) { var basex = r.Next(2, 62); var encoded = NumberToBase(i, basex); var decoded = NumberFromBase(encoded, basex); if (i != decoded) { Console.WriteLine( "i: {0} enc: {1} dec: {2}" , i, encoded, decoded); } } } |
No comments:
Post a Comment