Converting numbers into Roman numerals (1 Viewer)

Solo712

Registered User.
Local time
Today, 05:40
Joined
Oct 19, 2012
Messages
828
I need a general purpose VBA routine converting ordinals into Roman numerals. Did not want to spend much time on it. To my surprise my Google produced nothing much of value. Mind you, there are some smart blokes out there who propose to create value tables for the Roman letters and then go subtracting from the passed variable until they get the string. I suppose you can do it that way but I wouldn't sign my name on a piece of code which proposes to multiply two numbers by means of a lookup in a multiplication table.

Does anyone know an algorithm using directly the Roman numeral notation ? Can be in C/C++/Pascal etc....

Thanks in advance.

Best,
Jiri
 

Solo712

Registered User.
Local time
Today, 05:40
Joined
Oct 19, 2012
Messages
828
Check out this thread.


Thanks, John. In the meantime I created a modulo solution myself. I appended it to the thread (not realizing that it was 11 years old, silly me), in case anyone is interested.

Best,
Jiri
 

Solo712

Registered User.
Local time
Today, 05:40
Joined
Oct 19, 2012
Messages
828
Why not append it to this thread as well :)

Here ya go !:)

Basically, the Roman numerals are a decimal system with interval markers ('V', 'L' and 'D'). They prevent the same decimal digit (i.e. 'I', 'X',' C',' M') occuring more than three times in succession. It's all regular and orderly. Can be neatly decoded with a modulo logic.

Code:
Private Function Roman(x As Integer) As String
 
  If x < 1 Or x > 3999 Then
     Roman = "N/A"
     Exit Function
  End If
 
  Const Letters As String = "MDCLXVI"
  Dim i As Integer, o As Integer, s As Integer, t As Integer, rs As String
 
  rs = ""
 
  o = 1: s = 0
  For i = 7 To 1 Step -2
      t = (x Mod 10 ^ o - s) / 10 ^ (o - 1)
      Select Case t
        Case Is > 8
          rs = Mid(Letters, i, 1) & Mid(Letters, i - 2, 1) & rs
        Case Is > 4
           rs = Mid(Letters, i - 1, 1) & String(t - 5, Mid(Letters, i, 1)) & rs
        Case Is > 3
           rs = Mid(Letters, i, 1) & Mid(Letters, i - 1, 1) & rs
        Case Is > 0
           rs = String(t, Mid(Letters, i, 1)) & rs
      End Select
      s = t * 10 ^ (o - 1) + s
      o = o + 1
  Next i
  Roman = rs
End Function
 

Solo712

Registered User.
Local time
Today, 05:40
Joined
Oct 19, 2012
Messages
828
Though I don't need the opposite conversion (from Roman to decimal) I did one anyway, out of curiousity and to demo that the modulo logic can be used both ways. Here is the complementing routine.

Code:
[B]Private Function FromRoman(rs As String) As Integer[/B]
  Const Letters As String = "IVXLCDM"
  Dim i As Integer, o As Integer, pred As Integer, t As Integer
 
  ' set the predecessor digit value past the highest index  
  pred = 8   
 
  For i = 1 To Len(rs)
     o = InStr(Letters, Mid(rs, i, 1))
     If o Mod 2 = 1 Then
        t = t + 10 ^ (o \ 2)
     Else
        t = t + (10 ^ (o \ 2)) / 2
     End If
     ' if predecessor is lower index then current digit 
     ' remove the previous add and subtract the value
     ' from total instead
     If pred < o Then t = t - 2 * (10 ^ ((o - 2) \ 2))
     pred = o
  Next i
  FromRoman = t
[B]End Function[/B]

Somehow, I feel that this is the most efficient way to compute the conversion. But if someone has a better idea, I am all ears. :)

Best,
Jiri
 

fra

Registered User.
Local time
Today, 11:40
Joined
Nov 12, 2012
Messages
12
Jiri,
Here is an even shorter (and more elegant?) solution to Roman Numeral conversion which I found some time ago somewhere in the depths of Access Newsgroups:

Code:
Public Function RomanNumeral(ByVal aValue As Long) As String
  Dim i&
  Dim varArabic As Variant, varRoman As Variant
  Dim strResult As String

  varArabic = Array(1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000)
  varRoman = Array("I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M")

  For i = UBound(varArabic) To LBound(varArabic) Step -1
    Do While aValue >= varArabic(i)
      aValue = aValue - varArabic(i)
      strResult = strResult & varRoman(i)
    Loop
  Next i
  RomanNumeral = strResult
End Function

Fritz
 

Solo712

Registered User.
Local time
Today, 05:40
Joined
Oct 19, 2012
Messages
828
Jiri,
Here is an even shorter (and more elegant?) solution to Roman Numeral conversion which I found some time ago somewhere in the depths of Access Newsgroups:

Code:
Public Function RomanNumeral(ByVal aValue As Long) As String
  Dim i&
  Dim varArabic As Variant, varRoman As Variant
  Dim strResult As String
 
  varArabic = Array(1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000)
  varRoman = Array("I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M")
 
  For i = UBound(varArabic) To LBound(varArabic) Step -1
    Do While aValue >= varArabic(i)
      aValue = aValue - varArabic(i)
      strResult = strResult & varRoman(i)
    Loop
  Next i
  RomanNumeral = strResult
End Function

Fritz

Hi Fritz,
I don't want to wax contentious here on the eve of the Holy Night, but whatever this routine is (elegant, posh, glitzy, glamorous) it is not smart or efficient. Just a small proof of that : the longest number in the classical Roman system is 3888, i.e. MMMDCCCLXXXVIII, fifteen digits. How many ops does your friend's routine have to perform on the varArabic to get that number ? Looks to me like fifteen. Now, my routine needs only four passess no matter what the Roman digit equivalent to decimal. Why is that ? Because my routine is computing the Roman cipher, and his is looking it up in table, one abacus bead at a time. He fails to observe the mathematical order of the systems: i.e. that

the Roman "I" represents 10^0, "X" = 10^1, "C" = 10^2, M = 10^3. The interval markers are at midpoint: "V" = (10^1)/2, "L"=(10^2)/2, and "D" =(10^3)/2. You see the pattern ? If you do see it then you observe that the decimal digit in the order of thousands (i.e. 3 in our example of the long number), can be directly rendered as 3 Ms and need not be derived by to partitioning the digit to units. See what I'm saying ?

Have yourself great holidays, Fritz !

Best,
Jiri
 

fra

Registered User.
Local time
Today, 11:40
Joined
Nov 12, 2012
Messages
12
Jiri,
Season's Greetings to you too!
As it is not my code, I don't feel the urge to fight for it. You are right in pointing out that your code needs fewer iterations, which could be an issue when computing vast numbers of conversions in one batch. Also, mathematically, the beauty is definitively on your side.
Medieval users of the Roman numerals system came up with additional symbols to express even larger numbers economically.
Fritz
 

Users who are viewing this thread

Top Bottom