s c h e m a t i c s : c o o k b o o k

/ NumberRecipes / Cookbook.NumberRecipesRomanNumerals

This Web

TOC (with recipes)

Other Webs



Schematics Home
Sourceforge Page
Original Cookbook

Scheme Links

Scheme FAQ
Scheme Cross Reference
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe

Lambda the Ultimate

Working with Roman Numerals


You want to convert decimal numbers to Roman numerals and Roman numerals to decimal numbers.


First in the next code we can see the conversion between decimals numbers and Roman numerals.

; decimal->roman : integer -> string
;   format the integer num using roman numerals
(define (decimal->roman num)
  (let ((decimal-numbers (list 1000 900 500 400 100 90 50 40 10 9 5 4 1))
        (roman-numbers   (list "M" "CM" "D" "CD" "C" "XC" "L" 
                               "XL" "X" "IX" "V" "IV" "I")))
    (decimal->roman-aux num "" decimal-numbers roman-numbers)))

; decimal->roman-aux : integer string (list number) (list string) -> string
;   append the numbers num formatted as roman numerals to the string s,
;   using the roman numerals in roman-numbers with corresponding
;   decimal values in decimal-values
(define (decimal->roman-aux num s decimal-numbers roman-numbers)
  (if (null? decimal-numbers)
      (if (>= num (car decimal-numbers))
          (decimal->roman-aux (- num (car decimal-numbers)) 
                              (string-append s (car roman-numbers)) 
                              decimal-numbers roman-numbers)
          (decimal->roman-aux num s 
                              (cdr decimal-numbers) (cdr roman-numbers)))))

The solution for the convertion between Roman numerals and decimal numbers is shown in the next code.

(require (lib "13.ss" "srfi"))
(read-case-sensitive #t) ; due to the case expression

; roman->decimal : string -> integer
;  convert a string with (uppercase) roman numerals to an integer
(define (roman->decimal s)
    [(string= s "")              0]
    [(= (string-length s) 1)    (case (string->symbol s)
                                  [(I)     1]
                                  [(V)     5]
                                  [(X)    10]
                                  [(L)    50]
                                  [(C)   100]
                                  [(D)   500]
                                  [(M)  1000]
                                  [else    0])]
    [else                       (+ (roman->dec (string-drop s 2))
                                   (case (string->symbol (substring/shared s 0 2))
                                     [(IV)    4]
                                     [(IX)    9]
                                     [(XL)   40]
                                     [(XC)   90]
                                     [(CD)  400]
                                     [(CM)  900]
                                     [else    (+ (roman->dec (substring/shared s 0 1)) 
                                                 (roman->dec (string-drop s 1)))]))]))


In the first code we want to show a very simple solution, the main procedure call an auxiliary procedure that makes the real work. This procedure has 4 arguments: the number which we want to convert, the string that contains the result, the list that contains all the symbols that we can represent any roman numeral and the list that contains the same elements but in a decimal representation. Then we have 3 cases:

If the list decimal-numbers is empty we just return the string.

If the number is greater or equal than the first element of the decimals list we need to make a recursive call of this procedure but with the first argument as the rest between the number and the first element of the decimals list, and as a second argument an string that contains that we had and the first element of the roman numeral list and the other two arguments are the decimal and roman lists without changes.

If the number is less than the first element of the decimal list we just only make a recursive call with the number and the string unchanged and the decimal and roman lists without their first element. In the second code we use the srfi 13 that defines many procedures to manipulate strings, in other case it could be very difficult to resolve.

The main idea of the algorithm is recognize between two cases:

If the first character of the string is a simple symbol (I,V,X,L,C,D,M).

If the two first characters of the string are a double symbol (IV, IX, XL, XC, CD, CM).

Then we just sum the decimal values of the symbol that we have recognized.

-- EmiliaBarajas - 18 May 2004

TopicType: Recipe
ParentTopic: NumberRecipes
Next Topic: NumberRecipeRandomNumber

Copyright © 2004 by the contributing authors. All material on the Schematics Cookbook web site is the property of the contributing authors.
The copyright for certain compilations of material taken from this website is held by the SchematicsEditorsGroup - see ContributorAgreement & LGPL.
Other than such compilations, this material can be redistributed and/or modified under the terms of the GNU Lesser General Public License (LGPL), version 2.1, as published by the Free Software Foundation.
Ideas, requests, problems regarding Schematics Cookbook? Send feedback.
/ You are Main.guest