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

; 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)))))

(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)))]))]))

We have three cases to consider:

- If the list
`decimal-numbers`

is empty we just return the accumulator string, which is the value we are seeking. - Otherwise, we need to make a recursive call. There are two possibilities:
- If the number is greater than or equal to the first element of the decimals list:
- Use the difference of the first argument (the number to be converted) and the "value" of the roman numeral we are currently considering for the first argument.
- Append the roman numeral character currently being considered to the accumulator and pass this as the second argument.
- The other two arguments are the decimal and roman lists without changes.

- Otherwise, the number must be less than the first element of the decimal list:
- Use the input number without changes for the first argument.
- Use the existing accumulator string for the second argument.
- The final two arguments are the decimal and roman numeral lists (without their first element).

- If the number is greater than or equal to the first element of the decimals list:

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.

-- 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 |

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