Click here to Skip to main content
15,890,438 members
Articles / Programming Languages / C#
Article

Number base conversion class in C#

Rate me:
Please Sign up or sign in to vote.
4.43/5 (19 votes)
22 Dec 20063 min read 113.7K   4K   36   20
Library class to convert numbers between any number bases (from 2 to 36)

Sample Image - Convert.gif

Introduction

This library class converts numbers between a variety of number bases - in fact, any number base between 2 (binary) and 36. This goes beyond the .NET framework conversion libraries which offer a limited set of conversions

The library exposes a number of common conversions (such as Binary to Decimal/base10) for simple use as well as allowing user defined conversions under advanced use (such as base 26 to base 5)

Background

Recently I needed to calculate the numeric column ordinals for an Excel spreadsheet. Columns begin at 'A' and continue to 'B, ..., Z, AA, AB, ...' etc. I could not find any code to do this anywhere and also came across a number of posts on various coding sites asking how to perform conversions between arbitrary number bases

I solved my Excel requirement using a short function but decided it would be a useful exercise to develop a general number conversion class - this is the result. This class is generic enough to include handling the Excel scenario as well as all conventional number bases from 2 to 36 (inclusive)

The actual process of converting between bases is fairly trivial and I chose to convert to base 10 as an interim step. Therefore, when converting from base 3 to 7, for example, the code converts from base 3 to 10 then 10 to 7. I'm sure it is possible to develop a single algorithm to perform the conversion in one step so this may appear in a later version although I feel the current solution is easier to maintain and debug so maybe not

Code structure

There are 3 projects in the attached solution:

  • MarkGwilliam.com.Framework.Convert - Conversion class library
  • MarkGwilliam.com.Framework.Convert.Tests - Unit tests (requires NUnit)
  • MarkGwilliam.com.Framework.Convert.Demo - UI demo (see screenshot above)

Using the code

A simple demo is included. Download the code, open the solution, set the Demo project as startup and run. This will start the UI demo which you can use for simple conversions

In your own code, the Converter class can be used in a number of ways:

  • Simple use: built-in converters
  • Advanced use: custom converters
  • Advanced use: converter instances

...these are detailed below

Simple use: built-in converters

The simplest method is to use one of the 12 built-in static converters:

  • Convert.BinToDec.Convert()
  • Convert.BinToHex.Convert()
  • Convert.BinToOct.Convert()
  • Convert.DecToBin.Convert()
  • Convert.DecToHex.Convert()
  • etc.

This allows all conversion combinations using Binary, Octal, Decimal and Hexadecimal. For example:

// Convert FFFF (hex) to binary:

string binary = Converter.HexToBin.Convert("FFFF");

Advanced use: custom converters

In addition to the built-in static converters you can also perform custom conversion:

// Convert FFFF (hex) to base 5:

string base5 = Converter.Convert(NumberBases.Hexadecimal, 5, "FFFF");

Advanced use: converter instances

Converter instances can also be created instead of using the built-in static converters or the static Converter.Convert() methods (overloaded)

Instances are created using the static Converter.Create() factory methods which have a number of overloads. Once an instance is created, calls can be made to the Convert() method to perform conversions using the number bases specified when creating the converter instance

// base 26 (alphabet based) such as Excel column names --> decimal

Converter fromExcel = Converter.Create(26, NumberingSchemes.AToZ, NumberBases.Decimal,
                                       NumberingSchemes.ZeroToZ);

string columnNumber = fromExcel.Convert("AA");

Limitations

There are a few limitations to bear in mind:

  • Negative numbers are not supported
  • All converted values are returned as strings
  • The largest value that can be converted is Int64.MaxValue as long is used internally
  • Special character denoting number bases are not supported. For instance, Hexadecimal values are often written as 0xFF01 or &HFF01. This class requires the simpler FF01 notation

Points of Interest

The download includes unit tests (requires NUnit) which, apart from validating the conversions and testing class behaviour, also shows a number of other ways to use the class

The source is liberally commented and the associated documentation file (.CHM) is included

Further development

A couple of future plans:

  • Allow use of custom numbering strings. i.e. user defined symbols to use as digits
  • Support for number bases > 36

History

  • Version 1.0 - 1st Jan 2007 - Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect oo.magic
United Kingdom United Kingdom
Mark Gwilliam is a freelance .Net consultant based in the UK specialising in .Net architecture, design and coding.

He has been working in IT for around 15 years and has worked primarily in the financial sector and is always keen to lead, learn, follow or teach

Comments and Discussions

 
QuestionMaximum string length Pin
Bhavesh Maniya6-Jul-15 1:47
Bhavesh Maniya6-Jul-15 1:47 
AnswerPlease post a complete code using C# Pin
Reyden Mercado Quijano1-Sep-15 0:53
Reyden Mercado Quijano1-Sep-15 0:53 
QuestionThis Version has no Size Limit Pin
Joe Monnin31-Mar-14 16:07
Joe Monnin31-Mar-14 16:07 
GeneralRe: This Version has no Size Limit Pin
PIEBALDconsult31-Mar-14 17:07
mvePIEBALDconsult31-Mar-14 17:07 
GeneralRe: This Version has no Size Limit Pin
Joe Monnin3-Apr-15 7:55
Joe Monnin3-Apr-15 7:55 
QuestionCan find nunit.framework Pin
Member 100324516-May-13 7:40
Member 100324516-May-13 7:40 
QuestionAnother Way of Doing the Same Thing Pin
John d. Bartels16-Jan-12 12:43
John d. Bartels16-Jan-12 12:43 
Using the ideas you presented in your article, I was able to produce some code that converts from any base to any other base... Odd thing is, I did not use the convert class. I should mention that this code amounted to a mere 200 lines of code. I'm sure it could be improved upon further, but I will do my best to explain the code.

It essentially works to dynamically construct a numbering system based upon the users selection of the FromBase and the entered in Number.

User Enters Number xxx
User Selects FromBase
User Selects ToBase

x (being the first x starting from the left as numbers are most often read this way) is equal to the Value x * FromBase^indexLocation of x... for instance,

The Number 126 in Decimal:

so 1 represents 100
2 represents 20
and 6 represents 6
... simple

so the Number 1 which is in the index location 2 of the string of characters is equal to the value 1 * 10^2 or 1 * 100 or 100...
the Number 2 which is in the index location 1 of the string of characters is equal to the value 2 * 10^1 or 2* 10 or 20...
the Number 6 which is in the index location 0 of the string of characters is equal to the value 6 * 10^0 or 6* 1 or 6
The final Number is the sum of these three numbers... 100 + 20 + 6 = 126

*Note that the index location of the character was equal to the respective exponential power of the base for the place value the character resides in

The exponential values of the FromBase... in this case {1,10,100} can be saved in an array
The value of the Number String is inputted by the User i.e. string numString = userInputTextBox.Text;
If the FromBase is greater than 10, then an array of Characters to use for that Numbering System must be dynamically created.
If the ToBase is greater than 10, then an array of characters to use for that Numbering system must be dynamically created.

Method to Populate a Character List for Code to use dynamically:

private static List<NumberCharacter> populateCharacterList(int baseNumber)
{
    //this characterlist is a local list and is returned at the end of the method
    List<NumberCharacter> CharacterList2 = new List<NumberCharacter>();

    //This allows for the program to select from this array ... up to 26 characters beyond base-10 or... base-36
    char[] arrayChars = new 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' };

    char[] tempArray = arrayChars;
    int tempNumber = baseNumber;

    //this int will control which character is selected from the arraryChars Array
    int iterations = 0;
    int value = 0;
    do
    {
        if (value > 9)
        {
            NumberCharacter nctemp = new NumberCharacter();
            nctemp.DecNumber = value;
            nctemp.Character = tempArray[iterations];
            iterations++;
            CharacterList2.Add(nctemp);
            value++;
            tempNumber--;
        }
        else
        {
            NumberCharacter nctemp = new NumberCharacter();
            nctemp.DecNumber = value;
            nctemp.Character = (char)value;
            CharacterList2.Add(nctemp);
            value++;
            tempNumber--;
        }
    }
    while (tempNumber != 0);
    return CharacterList2;
}


A custom class to associate a specific Decimal Number such as 10 with a character value such as 'A':

C#
public class NumberCharacter
{
    public long DecNumber { get; set; }
    public char Character { get; set; }
}



Method to Return associated Decimal Number of Character Value:

C#
private static string getAssociatedDecimalNumberForCharacter(string passedString)
{
    foreach (NumberCharacter x in CharacterList)
    {
        if (x.Character.ToString() == passedString)
        {
            return x.DecNumber.ToString();
            break;
        }
    }
    return "^";
}



Method to Return associated Character Value of Decimal Number:

C#
private static string getAssociatedCharacterForDecimalNumber(long tempVal2)
{
    foreach (NumberCharacter x in CharacterList)
    {
        if(x.DecNumber == tempVal2)
        {
            return x.Character.ToString();
            break;
        }
    }

    return "^";
}


Of Course A method to Convert the Users Input into a Decimal Number:

public static string getDecimalNumberForPassedValue(string passedNumber, int fromBase)
{
    List<double> doubleList = new List<double>();

    List<string> characterList = new List<string>();
    List<string> resultsList = new List<string>();
    //intList.Add(1);
    double tempVal = 1;
    //We will add the Decimal Values of Each Place Value to a List
    for (int i = 0; i < passedNumber.Length; i++ )
    {
        doubleList.Add(tempVal);
        tempVal = tempVal * fromBase;
        string subString = passedNumber[passedNumber.Length - (i + 1)].ToString();
        //substring is an iteration of each character that is passed in... we can check to make sure the character is
        //not greater than the value of the fromBase...
        characterList.Add(subString);
    }

    double tempNumber2 = 0;
    for (int j = doubleList.Count - 1; j >= 0; j--)
    {
        double Num;
        bool isNum = double.TryParse(characterList[j], out Num);
        if (isNum)
        {
            if(double.Parse(characterList[j]) >= fromBase)
            {
                MessageBox.Show("Be Sure the Characters you are using Do not go Beyond the bounds of the Selected Numbering System... For Example, Do not use the letter A in a Decimal Number...");
                return "null";
            }
            else
            {
                double tempVal3 = doubleList[j] * double.Parse(characterList[j]);
                tempNumber2 = tempNumber2 + tempVal3;
            }

        }
        else
        {
            try
            {
                string tempString = getAssociatedDecimalNumberForCharacter(characterList[j]);
                if (double.Parse(tempString) >= fromBase)
                {
                    MessageBox.Show("Be Sure the Characters you are using Do not go Beyond the bounds of the Selected Numbering System... For Example, Do not use the letter A in a Decimal Number...");
                    return "null";
                }
                else
                {
                    //string tempString = getAssociatedDecimalNumberForCharacter(characterList[j]);
                    double tempVal3 = doubleList[j] * double.Parse(tempString);
                    tempNumber2 = tempNumber2 + tempVal3;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Be Sure the Characters you are using Do not go Beyond the bounds of the Selected Numbering System... For Example, Do not use the letter A in a Decimal Number..." + e.ToString());
                return "null";
                //break;
            }
        }
    }
    string resultsString = tempNumber2.ToString();
    return resultsString;
}



Last but not Least, A Method to Convert From Decimal to Any Other Base:

public static string CreateSelectedBaseNumberFromDecimal(double DecNumber, int baseNumber)
{
    //We will add the Decimal Values of Each Place Value's Exponential Value to a List
    //For instance, for decimal we would add 1, 10, 100, 1000, etc... These numbers represent the associated exponential value of the base
    //10^0 = 1; 10^1 = 10; 10^2 = 100... etc... because each value added to the list also has an index location... index location 0 for the value 1;
    // index location 1 for the value 10; index value 2 for the value 100... these index values also correspond to the associated exponential
    // power for that particular place value
    List<double> doubleList = new List<double>();

    List<string> resultsList = new List<string>();

    double tempVal = 1;
    double tempNumber = DecNumber;
    do
    {
        doubleList.Add(tempVal);
        tempVal = tempVal * baseNumber;
        if(tempVal > tempNumber)
        {
            tempNumber = 0;
        }
    }
    while (tempNumber != 0);
    double tempNumber2 = DecNumber;
    for (int i = doubleList.Count - 1; i >= 0; i--)
    {
        double tempVal2 = tempNumber2 / doubleList[i];
        double remainder = tempNumber2 % doubleList[i];
        if (tempVal2 > 0)
        {
            string tempString5 = tempVal2.ToString()[0].ToString();
            if (tempVal2 > 10)
            {
                tempString5 = getAssociatedCharacterForDecimalNumber(Int64.Parse(tempVal2.ToString().Substring(0, 2)));
                double subtractor = double.Parse(getAssociatedDecimalNumberForCharacter(tempString5)) * doubleList[i];
                resultsList.Add(tempString5);
                tempNumber2 = tempNumber2 - subtractor;
            }
            else
            {
                double subtractor = double.Parse(tempString5) * doubleList[i];
                resultsList.Add(tempVal2.ToString()[0].ToString());
                tempNumber2 = tempNumber2 - subtractor;
            }
        }
        else
        {
            resultsList.Add("0");
        }
    }
    //return tempNumber2.ToString();
    string resultsString = "";
    foreach(string x in resultsList)
    {
        resultsString = resultsString + x;
    }
    return resultsString;
}


Keeping in Mind that the user Told us what Base the Number Began in, we can convert the number into Decimal (for comprehension and translation sake)and then, convert the number into any other base.
QuestionMerci Pin
petite pomme29-Sep-11 5:21
petite pomme29-Sep-11 5:21 
GeneralDoesn't convert zero Pin
Darchangel27-Mar-09 4:17
Darchangel27-Mar-09 4:17 
GeneralRe: Doesn't convert zero Pin
John d. Bartels16-Jan-12 12:56
John d. Bartels16-Jan-12 12:56 
GeneralThank You Pin
Benjano5-Feb-09 5:43
professionalBenjano5-Feb-09 5:43 
GeneralGreat ... but Pin
mahpet20-Feb-08 10:32
mahpet20-Feb-08 10:32 
GeneralRe: Great ... but Pin
MarkGwilliam21-Feb-08 8:59
MarkGwilliam21-Feb-08 8:59 
GeneralRe: Great ... but Pin
#realJSOP31-Aug-08 1:50
mve#realJSOP31-Aug-08 1:50 
GeneralRe: Great ... but Pin
dzCepheus26-Mar-09 8:57
dzCepheus26-Mar-09 8:57 
GeneralVery useful class Pin
Lieven I29-Oct-07 1:05
Lieven I29-Oct-07 1:05 
GeneralRe: Very useful class Pin
MarkGwilliam29-Oct-07 9:32
MarkGwilliam29-Oct-07 9:32 
GeneralSimilar work Pin
rvdt7-Jan-07 22:20
rvdt7-Jan-07 22:20 
GeneralA sugestion... Pin
Stanciu Vlad23-Dec-06 22:39
Stanciu Vlad23-Dec-06 22:39 
GeneralNice Article Pin
Paul Conrad23-Dec-06 19:07
professionalPaul Conrad23-Dec-06 19:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.