Cool Code Revisited (by John Koziol)


So today Richard unveiled his version of a number to Roman numerals utility.  It involved a bit more processing than mine and used constants instead of a table. I thought that there was no way his was more efficient but when we ran speed tests, he beat me by a factor of 5X. Ugh.


I guess that goes to show you that it’s unwise to challenge a developer on his own turf <g>.


Anyhow, we had a team morale event today where everyone could go to a movie.  I stayed behind to research this whole Roman numerals issue.  Hey – made me happy so it lifted my morale! I wanted to extend the upper number limit beyond 3999 so I needed to see what the rules were for really big numbers.


What I found surprised me:  Apparently, there were several different ways to address this issue.  To keep it short, primarily,  the ancient Romans used a sort-of backwards C behind numbers to indicate addition zeroes and sometimes used the whole parentheses.  Hmm.  This was getting complicated.


What’s worse is that I discovered several different ways in which the numbers were coded, so the “traditional” way we are tought in school is really only some realtively modern standardization.


So….Richard beat me in speed but I subsequently got ’em in flexibility. I recoded my utility to be able to output all the different types and I also removed the table – instead, deriving values from a constant.  Probably faster, but with the added flexibility I can’t really do an apples to apples comparison with Richard’s code.


In case you’re interested (by the way, the categorization is mine and not academic at all – lol):


Roman Numerals:  I(1), V(5), X(10), L(50), C(100), D(500), M(1000)


Traditional Roman numerals are what is taught in school. They always use a subtractor to indicate a 4 or a 9. For example, 4 is “IV” and 9 is “IX”.  Values 1 through 3 of any tens grouping is represented by “n” number of the appropriate symbol; ie, 30 is XXX.  The value 1999 is, therefore, MCMXCIX. – lots of subtractor logic.


Ancient Roman numerals, that is, those actually used by the Romans are sort of flaky. While the traditional usage described above would be understood by any contemporary, very often they used a series of 4 of a symbol instead of the subtractor rule. However, this occurred primarily with 1 (“I”) and not as frequently with other symbols.  So, 29 could just as often be written as XXVIIII as XXIX. And 34 might be XXXIIII or XXXIV.  Apparently, the rooms in the Collisseum are numbered using the the IIII method.


“Clock” Roman numerals. An interesting story here. Older clocks in England always used “IIII” for 4 on the clockfaces, although they used “IX” for 9. Various theories have been proposed to account for this but the prevalent scholarly theory is that this came down from early monks in England writing in Latin and using the older, ne Ancient encoding.  Funny, though, Big Ben in London uses “IV”.


So those are the overall categories for basic numbers However, there’s a “style” modifier that can apply.


In medieval times, it was standard practice to show Roman numerals in lowercase. As you may or may not know, the Romans didn’t have a lowercase. But, when it was invented, it was used widely for Latin. Now here’s the stylistic kicker: Apparently, it was not considered good aesthetics to end a Roman numeral with a series of “I”s. So, if a number ended with more than one “I”, for example, 33 (XXXIII) it was considered good form to change the last I to a J.  All in lowercase, of course, so 33 became xxxiij.


So I modifed my code to accept a second parameter of “A”,”C”, or “T” and a “M” could be tacked on to show the results in medieval fashion.


Now, I have no intention of posting code here which – in large part – would be a duplicate of what I already posted but anyone who wants the revised code, or Richard’s solution, is welcome to email me and I’ll send it to them. jkoziol@microsoft.com


BTW, at Richard’s urging I also wrote a Roman to decimal converter which is short and cool and I’ll send that too should you want it.


This was a lot of fun.  I love algorithms!


 


Comments (3)

  1. Craig Boyd says:

    When I read that you guys were having a contest I couldn’t resist. <g> I’ve traded of some speed to reduce the overall size of the program, but it’s still pretty fast (.3 of a second is the average run at this end) and it creates a results cursor with 1-3999 and their Roman Numeral equivalents. Anyways, here’s my 18 code lines for consideration (cut-n-paste into a prg and execute it)…

    #DEFINE ROMANNUMERALS "I IV V IX X XL L XC C CD D CM M"

    #DEFINE VALUESTRING "1 4 5 9 10 40 50 90 100 400 500 900 1000"

    CREATE CURSOR RomanDec (romanequiv c(15), decequiv n(4))

    FOR nNextDec = 1 TO 3999

    nNum = nNextDec

    cReturn = ""

    FOR nCounter = 13 TO 1 STEP – 1

    nRomanValue = VAL(GETWORDNUM(VALUESTRING, nCounter))

    nReplicate = INT(nNum/nRomanValue)

    IF nReplicate > 0

    cRomanLetter = GETWORDNUM(ROMANNUMERALS, nCounter)

    cReturn = cReturn + REPLICATE(cRomanLetter, nReplicate)

    nNum = MOD(nNum, nReplicate * nRomanValue)

    ENDIF

    ENDFOR

    INSERT INTO RomanDec (romanequiv, decequiv) VALUES (cReturn, nNextDec)

    ENDFOR

    BROWSE

  2. vsdata says:

    (Koziol here)

    Not bad, Craig!

    Here’s mine with input routines and error trapping stripped, for comparison:

    * cNum = the Roman numeral

    #DEFINE RSYMBS " IVXLCDM"

    STORE 0 TO nVal,nAmount,nModifier

    cLastSymb="I"

    nFailType=0

    FOR i = LEN(cNum) TO 1 STEP -1

    cCurrSymb=SUBSTR(cNum,i,1)

    nSymPos=ATC(cCurrSymb,RSYMBS)

    nModifier=IIF(nSymPos < ATC(cLastSymb,RSYMBS),-1,1)

    nAmount=(10^(INT(nSympos/2)-1)*IIF(MOD(nSymPos,2)#0,5,1)) * nModifier

    nVal=nVal+nAmount

    cLastSymb=cCurrSymb

    ENDFOR

    ?nVal