Roman Number Conversion

This is an update of an older post describing a short program written in ALGOL 68 to convert strings of roman numbers to decimal integer values.

For no particular reason I decided to rewrite this using two operators to do the roman number conversion for a single roman numeral (the simplest case) and strings of roman numbers, and I added a simple procedure to print and check the results. I think the resulting code is a little more ‘elegant’ but that is just my personal view.

{ Roman number conversion - 10 Jan 16 - MEJT }

PROGRAM roman

  { This program is free software: you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the Free
  Software Foundation, either version 3 of the License, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  for more details.

  You should have received a copy of the GNU General Public License along
  with this program.  If not, see <http://www.gnu.org/licenses/>

(
  OP DECIMAL = (CHAR roman) INT:

  { Degenerate case corresponding to a single roman numeral, used
    when parsing longer strings of roman numerals. An unrecognized
    numeral or null string will return the value zero.

    Note - To make the code more readable the tokenized syntax of the
    if-then statement has been used. }

    ( roman = "M" | 1000 |:
      roman = "D" |  500 |:
      roman = "C" |  100 |:
      roman = "L" |   50 |:
      roman = "X" |   10 |:
      roman = "V" |    5 |:
      roman = "I" |    1 | 0);

  OP DECIMAL = (STRING roman) INT:

  { Overloaded definition of the operator for more complex strings of roman
    numerals. }

    ( INT result := 0, last := 0, run := 0;
      FOR i FROM LWB roman TO UPB roman DO
        INT value = DECIMAL(roman[i]);
        IF last = value THEN
          run +:= value
        ELSE
          IF last < value THEN
            result -:= run
          ELSE
            result +:= run
          FI;
          run := last := value
        FI
      OD;
      result +:= run );

  PRIO DECIMAL = 9;

  PROC check = (STRING roman, INT value) VOID:
    ( write ((roman," "*(12-UPB(roman)),"= ", fixed(DECIMAL(roman),-6,0),
      ((DECIMAL(roman) = value | " - Ok" | " - Error")),
      newline)) );

  check ("MMXI",2011);
  check ("MIM", 1999);
  check ("MCMXCIX", 1999);
  check ("MCMLXIII", 1963);
  check ("MDCLXIV", 1664);
  check ("XXCIII", 83);
  check ("LXXIIX", 78);
  check ("MDCCCCX", 1910);
  write (newline);
  check ("IX", 9);
  check ("VII", 7);
  check ("V", 5);
  check ("IV", 4);
  check ("III", 3);
  check ("II", 2);
  check ("I", 1);
  check ("", 0) )

FINISH.

The program produces the following output. Both possible forms for 1999 are handled correctly but while ‘MIM’ is shorter and more convenient, the longer version ‘MCMXCIX’ is normally used.

MMXI        =   2011 - Ok
MIM         =   1999 - Ok
MCMXCIX     =   1999 - Ok
MCMLXIII    =   1963 - Ok
MDCLXIV     =   1664 - Ok
XXCIII      =     83 - Ok
LXXIIX      =     78 - Ok
MDCCCCX     =   1910 - Ok

IX          =      9 - Ok
VII         =      7 - Ok
V           =      5 - Ok
IV          =      4 - Ok
III         =      3 - Ok
II          =      2 - Ok
I           =      1 - Ok
            =      0 - Ok

Algol68g Notes

To run this example on a modern system using Algol68g then you will need to make a couple of minor changes to my code.

  • Comments should be delimited using ‘#’ rather than ‘{‘ and ‘}’
  • The ‘PROGRAM’ and ‘FINISH’ statements should be omitted, but you do need to start your program with an opening bracket (or ‘BEGIN’).
This entry was posted in Programming and tagged . Bookmark the permalink.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.