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

/ WebHome / TOC / NumberChapter / Cookbook.NumberRecipesRomanNumerals

This Web


WebHome 
WebChanges 
TOC (with recipes)
NewRecipe 
WebTopicList 
WebStatistics 

Other Webs


Chicken
Cookbook
Erlang
Know
Main
Plugins
Sandbox
Scm
TWiki  

Schematics


Schematics Home
Sourceforge Page
SchemeWiki.org
Original Cookbook
RSS

Scheme Links


Schemers.org
Scheme FAQ
R5RS
SRFIs
Scheme Cross Reference
PLT Scheme SISC
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe
GaucheChez

Lambda the Ultimate
TWiki.org

Working with Roman Numerals

Problem

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

Solution

Here is some example code illustrating 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)
      s
      (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)))))

And here is the reverse transformation (converting between Roman numerals and decimal numbers):
(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)
  (cond
    [(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)))]))]))

Discussion

In the first code sample we show a very simple solution; the main procedure takes the number to be converted. It then calls an auxilliary procedure that performs the actual conversion. The auxilliary procedure takes four arguments: (1) the number we want to convert, (2) an accumulator string that will (eventually) contain the result, (3) a list containing the decimal integers that we can represent as roman numerals, and (4) a list of corresponding roman numeral representations of the decimal values.

We have three cases to consider:

In the second code example we use SRFI 13 that defines many procedures for manipulating strings. This problem would be difficult to solve without those helpful implementations.

The main idea of this algorithm is two handle two cases: (1) The first character of the string is a simple symbol (an atom) (I,V,X,L,C,D,M); and (2) the first two characters of the string form a double symbol (IV, IX, XL, XC, CD, CM).

Once we determine which condition we are dealing with, we just sum the decimal values of the symbol that we have recognized.

Contributors

-- EmiliaBarajas - 18 May 2004

Substantially revised the text of the recipe, but the coding is unchanges. -- BrentAFulgham - 24 Aug 2004

CookbookForm
TopicType: Recipe
ParentTopic: NumberRecipes
TopicOrder: 060

 
 
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