Introduction
In the whole arena of computer programming, there exists the problem to convert a number from one number system to another. I want to solve it in a more generic way to support more than one conversion scheme in future. In the following article, I want to explain four systems that were implemented into the xProcs.Common.Converter
namespace.
- Roman number system, i.e., X, MCDXIII
- Hexadecimal, i.e., $FA
- Octal, i.e., o4571
- Binary, i.e., 001010111011
Using the code
To use one concrete conversion, you simple use the ConverterBase
class and access the converter over a static property. The following example writes out the Roman number for the year 1984:
Console.WriteLine(ConverterBase.Roman.ToString(1984));
The other direction works the same:
Console.WriteLine(ConverterBase.Roman.ToInt("MCMLXXXIV"));
Static singleton property
If you look into the code, you'll see some things I love to do in the code. For example I define a static getter for accessing an instance of the concrete converter. It's a lazy creation, the instancing is done at the first access of the property!
private static volatile ConverterBase binary;
static public ConverterBase Roman
{
get
{
if (roman == null)
roman = new RomanConverter();
return roman;
}
}
Hexadecimal, octal and binary systems
These three conversions all use the class PositionalNotationConverter
, because they share the same functionality and all are based on a radix of 2, 4 or 8. I only create the class converter with a different radix, that's all.
hexadecimal = new PositionalNotationConverter(16);
Roman number system
This number system is a little more tricky but it is possible to implement a converter. Some use-cases for this converter are in numbering the contents in a document: I. II. III. and so on, or to show years in longer format like you see often in films. In the code, you'll see at first, the check for MAX
. Bigger numbers than MAX
aren't valid in the Roman-system. After this, for each digit, an index is calculated and then a simple predefined lookup-table is used to get the Roman digits.
public override string ToString(int value)
{
if (value > MAX)
throw new ArgumentOutOfRangeException("value");
string[,] romanDigits = new string[,] {
{"M", "C", "X", "I" },
{"MM", "CC", "XX", "II" },
{"MMM", "CCC", "XXX", "III" },
{null, "CD", "XL", "IV" },
{null, "D", "L", "V" },
{null, "DC", "LX", "VI" },
{null, "DCC", "LXX", "VII" },
{null, "DCCC", "LXXX", "VIII" },
{null, "CM", "XC", "IX" }
};
StringBuilder result = new StringBuilder(15);
for (int index = 0; index < 4; index++)
{
int power = (int) Math.Pow(10, 3 - index);
int digit = value / power;
value -= digit * power;
if (digit > 0)
result.Append(romanDigits[digit - 1,index]);
}
return result.ToString();
}
For converting a Roman number back, the following code is used. Here the trick is to remember the old value. If it's greater than the current value it is reduced twice by the old value. Else it is only added. The RomanDigit
function gives you back the value for a single Roman digit.
public override int ToInt(string number)
{
int result = 0;
int oldValue = 1000;
for (int index = 0; index < number.Length; index++)
{
int newValue = RomanDigit(number[index]);
if (newValue > oldValue)
result = result + newValue - 2 * oldValue;
else
result += newValue;
oldValue = newValue;
}
return result;
}
Test-Case's
Here you see the test-cases I've written for the four conversion classes. That's how I check if my code works against one or more test scenarios.
[TestFixture]
public class NumberConvertTest
{
[Test]
public void RomanNumber()
{
Assert.AreEqual("MCMLXXXIV", ConverterBase.Roman.ToString(1984));
Assert.AreEqual(1984, ConverterBase.Roman.ToInt("MCMLXXXIV"));
}
[Test]
public void HexNumber()
{
Assert.AreEqual("12FEAC", ConverterBase.Hexadecimal.ToString(0x12FeAC));
Assert.AreEqual(0x12FeAC, ConverterBase.Hexadecimal.ToInt("12FEAC"));
}
[Test]
public void OctNumber()
{
Assert.AreEqual("4553207", ConverterBase.Octal.ToString(1234567));
Assert.AreEqual(1234567, ConverterBase.Octal.ToInt("4553207"));
}
[Test]
public void BinaryNumber()
{
Assert.AreEqual("1010111111111110", ConverterBase.Binary.ToString(0xAFFE));
Assert.AreEqual(0xAFFE, ConverterBase.Binary.ToInt("1010111111111110"));
}
}
Summary
Okay, I hope that you like the code and can use it in your own projects. I want to hear from you your opinion about it. If you have your own conversion methods inherited from ConverterBase
please send it to me, if you wish that I include it into the xProcs.Common.Converter
namespace.
History
About xProcs
xProcs is a free collection of methods that you can use in your own projects. If you have ideas or code to be included in this collection, send it to xProcs@hotmail.de.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.