Library tutorials & articles
Number Systems
By Mitch Dusina, published on 16 Dec 2005
Page 5 of 5
- The Different Systems
- Any To Decimal
- Decimal To Any
- Any To Any
- Roman Numerals
Roman Numerals
And finally, we come to Roman Numerals. They are roughly
equivelent to something that we would write as "100 + 50 + 10 +
1". In other words, they are
baseless.
'The following are the 14 different valid letter combinations_
'for Roman Numerals
'and what they equal. It is improper (for whatever reason) to_
'say "IM = 999",
'you must say "CMXCIX".
Public Enum RomanNumerals As Integer
N = 0
I = 1
IV = 4
V = 5
IX = 9
X = 10
XL = 40
L = 50
XC = 90
C = 100
CD = 400
D = 500
CM = 900
M = 1000
End Enum
Public Function FromRomanNumeral(ByVal Number As String) As Long
Number = Number.ToUpper
Dim chrRomans() As Char = Number.ToCharArray
Dim intRomanParse(Number.Length) As Integer
Dim lRoman As Long
Dim i As Integer
Dim iCounter As Int16
'Basically, steps through the Roman Numeral string looking for
'valuesin the RomanNumerals Enum
For i = Number.Length - 1 To 0 Step -1
Select Case chrRomans(i).ToString
Case "N" '0
intRomanParse(i) = RomanNumerals.N
Case "I" '1
intRomanParse(i) = RomanNumerals.I
Case "V" '5
If i > 0 AndAlso chrRomans(i - 1).ToString = "I" Then
intRomanParse(i) = RomanNumerals.IV
'Used if an extended digit is present since they use_
'2 letters
i -= 1
Else
intRomanParse(i) = RomanNumerals.V
End If
Case "X" '10
If i > 0 AndAlso chrRomans(i - 1).ToString = "I" Then
intRomanParse(i) = RomanNumerals.IX
'Used if an extended digit is present since they use_
'2 letters
i -= 1
Else
intRomanParse(i) = RomanNumerals.X
End If
Case "L" '50
If i > 0 AndAlso chrRomans(i - 1).ToString = "X" Then
intRomanParse(i) = RomanNumerals.XL
'Used if an extended digit is present since they use_
'2 letters
i -= 1
Else
intRomanParse(i) = RomanNumerals.L
End If
Case "C" '100
If i > 0 AndAlso chrRomans(i - 1).ToString = "X" Then
intRomanParse(i) = RomanNumerals.XC
'Used if an extended digit is present since they use_
'2 letters
i -= 1
Else
intRomanParse(i) = RomanNumerals.C
End If
Case "D" '500
If i > 0 AndAlso chrRomans(i - 1).ToString = "C" Then
intRomanParse(i) = RomanNumerals.CD
'Used if an extended digit is present since they use_
'2 letters
i -= 1
Else
intRomanParse(i) = RomanNumerals.D
End If
Case "M" '1000
If i > 0 AndAlso chrRomans(i - 1).ToString = "C" Then
intRomanParse(i) = RomanNumerals.CM
'Used if an extended digit is present since they use_
'2 letters
i -= 1
Else
intRomanParse(i) = RomanNumerals.M
End If
Case Else 'Not a digit
Throw New Exception(Number & " is not a valid Roman_
Numeral because it contains the symbol:_
" & chrRomans(i).ToString & ".")
End Select
Next
For i = 0 To Number.Length
lRoman += intRomanParse(i)
Next
Return lRoman
End Function
Public Function ToRomanNumeral(ByVal Number As Long) As String
Dim strRoman As String
Dim intM, intCM, intD, intCD, intC, intXC, intL, intXL, intX,_
intIX, intV, intIV, intI As Short
Dim i As Short
If Number = 0 Then Return "N"
'How many integral times does "M" go into the number?
intM = Number \ RomanNumerals.M
Number -= intM * RomanNumerals.M
'How many integral times does "CM" go into the number?
intCM = Number \ RomanNumerals.CM
Number -= intCM * RomanNumerals.CM
'How many integral times does "D" go into the number?
intD = Number \ RomanNumerals.D
Number -= intD * RomanNumerals.D
'How many integral times does "CD" go into the number?
intCD = Number \ RomanNumerals.CD
Number -= intCD * RomanNumerals.CD
'How many integral times does "C" go into the number?
intC = Number \ RomanNumerals.C
Number -= intC * RomanNumerals.C
'How many integral times does "XC" go into the number?
intXC = Number \ RomanNumerals.XC
Number -= intXC * RomanNumerals.XC
'How many integral times does "L" go into the number?
intL = Number \ RomanNumerals.L
Number -= intL * RomanNumerals.L
'How many integral times does "XL" go into the number?
intXL = Number \ RomanNumerals.XL
Number -= intXL * RomanNumerals.XL
'How many integral times does "X" go into the number?
intX = Number \ RomanNumerals.X
Number -= intX * RomanNumerals.X
'How many integral times does "IX" go into the number?
intIX = Number \ RomanNumerals.IX
Number -= intIX * RomanNumerals.IX
'How many integral times does "V" go into the number?
intV = Number \ RomanNumerals.V
Number -= intV * RomanNumerals.V
'How many integral times does "IV" go into the number?
intIV = Number \ RomanNumerals.IV
Number -= intIV * RomanNumerals.IV
'How many integral times does "I" go into the number?
intI = Number \ RomanNumerals.I
Number -= intI * RomanNumerals.I
'Puts together all the pieces
For i = 1 To intM
strRoman &= "M"
Next
For i = 1 To intCM
strRoman &= "CM"
Next
For i = 1 To intD
strRoman &= "D"
Next
For i = 1 To intCD
strRoman &= "CD"
Next
For i = 1 To intC
strRoman &= "C"
Next
For i = 1 To intXC
strRoman &= "XC"
Next
For i = 1 To intL
strRoman &= "L"
Next
For i = 1 To intXL
strRoman &= "XL"
Next
For i = 1 To intX
strRoman &= "X"
Next
For i = 1 To intIX
strRoman &= "IX"
Next
For i = 1 To intV
strRoman &= "V"
Next
For i = 1 To intIV
strRoman &= "IV"
Next
For i = 1 To intI
strRoman &= "I"
Next
Return strRoman
End Function
'This function will take an incorrectly formated Roman Numeral and_
'return it in it's corrected form ("CMXCIXVIII" becomes "MVII")
Public Function CorrectRomanNumeral(ByVal Number As String) As String
Dim lRoman As Long = FromRomanNumeral(Number)
Return ToRomanNumeral(lRoman)
End Function
Related articles
Related discussion
-
ditto
by zapthedingbat (2 replies)
-
Mousewheel
by jonh (3 replies)
-
True multithread VB source code controls
by James Crowley (3 replies)
-
Rely
by Yujvendra Verma (4 replies)
-
True multithread VB source code controls
by James Crowley (3 replies)

I have just returned from an extended absence from this forum so I realize this is rather late.
It looks good, the only thing I can spot is the line where you catch the Exception. Not finding an extended numeral is expected (and common at that), so an Exception shouldn't be used to control the flow of code.
Although I can't think of an easy way around it since they removed Enum.TryParse (2.0 and later I think).
Thanks for the Roman Numeral example! I made some equivalent functions in C# using Enum's static methods. This results in more concise versions of the two primary methods described in the article. They have been named a little bit differently to suit my tastes, but are the same methods in terms of the algorithm used. This code also uses the exact same RomanNumerals enum (which I haven't included in this snippet). Feel free to suggest further improvements, or to translate this back to VB.NET:
private int ParseRomanNumeral(string numeral)
{
numeral = numeral.ToUpper();
char[] characters = numeral.ToCharArray();
int[] parseBuf = new int[numeral.Length];
int result = 0;
bool bSkip = false;
for (int i = numeral.Length - 1; i >= 0; i--)
{
if (bSkip)
{
bSkip = false; // Skip this digit because it is part of a 2-digit numeral
continue;
}
parseBuf[i] = (int)Enum.Parse(typeof(RomanNumerals), characters[i].ToString());
if (parseBuf[i] % 5 == 0 && i > 0)
{
string extended = characters[i-1].ToString() + characters[i].ToString();
try
{
parseBuf[i] = (int)Enum.Parse(typeof(RomanNumerals), extended);
bSkip = true;
}
catch(ArgumentException)
{
// Ignore this exception. It just means we didn't find an extended numeral
}
}
}
for (int i = 0; i < numeral.Length; i++)
{
result += parseBuf[i];
}
return result;
}
private string ConvertToRomanNumeral(int num)
{
string sResult = "";
sResult = Enum.GetName(typeof(RomanNumerals), num);
if (sResult == null)
{
string[] names = Enum.GetNames(typeof(RomanNumerals));
int[] vals = (int[])Enum.GetValues(typeof(RomanNumerals));
for (int i = names.Length - 1; i > 0; i--) // Don't process the 0th element, since it is 0 and results in bad math
{
int temp = num / vals[i];
num -= temp * vals[i];
for (int j = 0; j < temp; j++)
{
sResult += names[i];
}
}
}
return sResult;
}