Roman numerals/Encode: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 312: Line 312:
: >roman ( n -- str )
: >roman ( n -- str )
dup roman-range-check [ (>roman) ] "" make ;
dup roman-range-check [ (>roman) ] "" make ;

=={{header|Fan}}==
<lang Fan>
**
** converts a number to its roman numeral representation
**
class RomanNumerals
{

private Str digit(Str x, Str y, Str z, Int i)
{
switch (i)
{
case 1: return x
case 2: return x+x
case 3: return x+x+x
case 4: return x+y
case 5: return y
case 6: return y+x
case 7: return y+x+x
case 8: return y+x+x+x
case 9: return x+z
}
return ""
}

Str toRoman(Int i)
{
if (i>=1000) { return "M" + toRoman(i-1000) }
if (i>=100) { return digit("C", "D", "M", i/100) + toRoman(i%100) }
if (i>=10) { return digit("X", "L", "C", i/10) + toRoman(i%10) }
if (i>=1) { return digit("I", "V", "X", i) }
return ""
}

Void main()
{
2000.times |i| { echo("$i = ${toRoman(i)}") }
}

}
</lang>


=={{header|Forth}}==
=={{header|Forth}}==

Revision as of 03:08, 6 May 2009

Task
Roman numerals/Encode
You are encouraged to solve this task according to the task description, using any language you may know.

Create a function taking a positive integer as its parameter and returning a string containing the Roman Numeral representation of that integer.

Modern Roman numerals are written by expressing each digit separately starting with the left most digit and skipping any digit with a value of zero. In Roman numerals 1990 is rendered: 1000=M, 900=CM, 90=XC; resulting in MCMXC. 2008 is written as 2000=MM, 8=VIII; or MMVIII. 1666 uses each Roman symbol in descending order: MDCLXVI.

Ada

<lang ada> with Ada.Text_IO; use Ada.Text_IO;

procedure Roman_Numeral_Test is

  function To_Roman (Number : Positive) return String is
     subtype Digit is Integer range 0..9;
     function Roman (Figure : Digit; I, V, X : Character) return String is
     begin
        case Figure is
           when 0 => return "";
           when 1 => return "" & I;
           when 2 => return I & I;
           when 3 => return I & I & I;
           when 4 => return I & V;
           when 5 => return "" & V;
           when 6 => return V & I;
           when 7 => return V & I & I;
           when 8 => return V & I & I & I;
           when 9 => return I & X;
        end case;
     end Roman;
  begin
     pragma Assert (Number >= 1 and Number < 4000);
     return
        Roman (Number / 1000,       'M', ' ', ' ') &
        Roman (Number / 100 mod 10, 'C', 'D', 'M') &
        Roman (Number / 10 mod 10,  'X', 'L', 'C') &
        Roman (Number mod 10,       'I', 'V', 'X');
  end To_Roman;

begin

  Put_Line (To_Roman (1999));
  Put_Line (To_Roman (25));
  Put_Line (To_Roman (944));

end Roman_Numeral_Test; </lang> Output:

MCMXCIX
XXV
CMXLIV

ALGOL 68

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
Works with: ELLA ALGOL 68 version Any (with appropriate job cards AND formatted transput statements removed) - tested with release 1.8.8d.fc9.i386

<lang algol> []CHAR roman = "MDCLXVmdclxvi"; # UPPERCASE for thousands # []CHAR adjust roman = "CCXXmmccxxii"; []INT arabic = (1000000, 500000, 100000, 50000, 10000, 5000, 1000, 500, 100, 50, 10, 5, 1); []INT adjust arabic = (100000, 100000, 10000, 10000, 1000, 1000, 100, 100, 10, 10, 1, 1, 0);

PROC arabic to roman = (INT dclxvi)STRING: (

 INT in := dclxvi; # 666 #
 STRING out := "";
 FOR scale TO UPB roman WHILE in /= 0 DO
   INT multiples = in OVER arabic[scale];
   in -:= arabic[scale] * multiples;
   out +:= roman[scale] * multiples;
   IF in >= -adjust arabic[scale] + arabic[scale] THEN
     in -:= -adjust arabic[scale] + arabic[scale];
     out +:=  adjust roman[scale] +  roman[scale]
   FI
 OD;
 out

);

main:(

 []INT test = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,25,30,40,50,60,69,70,
    80,90,99,100,200,300,400,500,600,666,700,800,900,1000,1009,1444,1666,1945,1997,1999,
    2000,2008,2500,3000,4000,4999,5000,6666,10000,50000,100000,500000,1000000,max int);
 FOR key TO UPB test DO
   INT val = test[key];
   print((val, " - ", arabic to roman(val), new line))
 OD

)</lang> Output:

         +1 - i
         +2 - ii
         +3 - iii
         +4 - iv
         +5 - v
         +6 - vi
         +7 - vii
         +8 - viii
         +9 - ix
        +10 - x
        +11 - xi
        +12 - xii
        +13 - xiii
        +14 - xiv
        +15 - xv
        +16 - xvi
        +17 - xvii
        +18 - xviii
        +19 - xix
        +20 - xx
        +25 - xxv
        +30 - xxx
        +40 - xl
        +50 - l
        +60 - lx
        +69 - lxix
        +70 - lxx
        +80 - lxxx
        +90 - xc
        +99 - xcix
       +100 - c
       +200 - cc
       +300 - ccc
       +400 - cd
       +500 - d
       +600 - dc
       +666 - dclxvi
       +700 - dcc
       +800 - dccc
       +900 - cm
      +1000 - m
      +1009 - mix
      +1444 - mcdxliv
      +1666 - mdclxvi
      +1945 - mcmxlv
      +1997 - mcmxcvii
      +1999 - mcmxcix
      +2000 - mm
      +2008 - mmviii
      +2500 - mmd
      +3000 - mmm
      +4000 - mV
      +4999 - mVcmxcix
      +5000 - V
      +6666 - Vmdclxvi
     +10000 - X
     +50000 - L
    +100000 - C
    +500000 - D
   +1000000 - M
+2147483647 - MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMCDLXXXmmmdcxlvii

C

<lang c>#include <stdlib.h>

  1. include <stdio.h>

void roman(char *s, unsigned n) /* Writes the Roman numeral representing n into the buffer s. Handles up to n = 3999. Since C doesn't have exceptions, n = 0 causes the whole program to exit unsuccessfully. s should be have room for at least 16 characters, including the trailing null. */

{if (n == 0)
    {puts("Roman numeral for zero requested.");
     exit(EXIT_FAILURE);}
 #define digit(loop, num, c) \
     loop (n >= num)         \
        {*(s++) = c;         \
         n -= num;}  
 #define digits(loop, num, c1, c2) \
     loop (n >= num)               \
        {*(s++) = c1;              \
         *(s++) = c2;              \
         n -= num;}
 digit  ( while, 1000, 'M'      )
 digits ( if,     900, 'C', 'M' )
 digit  ( if,     500, 'D'      )
 digits ( if,     400, 'C', 'D' )
 digit  ( while,  100, 'C'      )
 digits ( if,      90, 'X', 'C' )
 digit  ( if,      50, 'L'      )
 digits ( if,      40, 'X', 'L' )
 digit  ( while,   10, 'X'      )
 digits ( if,       9, 'I', 'X' )
 digit  ( if,       5, 'V'      )
 digits ( if,       4, 'I', 'V' )
 digit  ( while,    1, 'I'      )
 #undef digit
 #undef digits
 
 *s = 0;}

int main(void)

 {char buffer[16];
  for (int i = 1 ; i < 4000 ; ++i)
     {roman(buffer, i);
      printf("%4d: %s\n", i, buffer);}
  return 1;}</lang>

An alternative version which builds the string backwards. <lang c>char *ToRoman(int num, char *buf, int buflen) {

  static char *romanDgts = "ivxlcdmVXLCDM_";
  char *roman = buf + buflen;
  int  rdix, r, v;
  *--roman = '\0';        /* null terminate return string */
  if (num >= 4000000) {
     printf("Number Too Big.\n");
     return NULL;
     }
  for (rdix = 0; rdix < strlen(romanDgts); rdix += 2) {
     if (num == 0) break;
     v = (num % 10) / 5;
     r = num % 5;
     num = num / 10;
     if (r == 4) {
        if (roman < buf+2) {
           printf("Buffer too small.");
           return NULL;
           }
        *--roman = romanDgts[rdix+1+v];
        *--roman = romanDgts[rdix];
        }
     else {
        if (roman < buf+r+v) {
           printf("Buffer too small.");
           return NULL;
           }
        while(r-- > 0) {
           *--roman = romanDgts[rdix];
           }
        if (v==1) {
           *--roman = romanDgts[rdix+1];
           }
        }
     }
  return roman;

}</lang>

Common Lisp

 (defun roman-numeral (n)
   (format nil "~@R" n))

D

This implementation in generally follows the rules implied by Modern Roman numerals, with some irregularity depend on whether numerals larger than M(1000) is used, eg. 4000 is converted to MV' if V' is used, MMMM if not. <lang d>module roman ; import std.stdio ;

const string[] Roman = ["V","X","L","C","D","M","I"] ; const int RLen = Roman.length - 1 ; const int[][] RDigit =

 [[0],[0,0],[0,0,0],[0,1],[1],[1,0],[1,0,0],[1,0,0,0],[0,2],[0,0,0,0]] ;

const string[] Power = ["", "'","\"","`","~","^","#"] ; // arbitary _power_ symbols, or

           // Power = ["1","2","3","4","5","6","7"] ;  // for easier further processing

const int[][] Shift = [[0,0,0],[-1,0,0]] ;

string romanPart(int n, int part, bool extented) {

 if (n == 0) return "" ;
 int[3] b ;  
 b[1] = (2 * part) % RLen ;
 b[0] = part == 0 ? RLen : (RLen + b[1] - 1) % RLen ;
 b[2] = b[1] + 1 ;
 int power = part / 3 ;
 int[] shift = Shift[ b[1] == 0 && part != 0 ? 1 : 0] ;
 int[] Digit = !extented && n == 4 && part == 3 ? RDigit[$-1]  : RDigit[n-1]  ;
 string res ;
 foreach(inx ; Digit)
   res ~= Roman[b[inx]] ~ Power[power + shift[inx]] ;
 return res ;

} string toRoman(long n, bool extented = true) {

 if(n < 0) throw new Exception("No negative Roman Numeral") ;
 if(n == 0) return "" ;
 if(!extented && n >= 5000) throw new Exception("Only smaller than 5000 allowed") ;
 string romans ;
 int part = 0 ;
 while (n > 0) {
   long m = n / 10 ;
   romans = romanPart(n - m*10, part, extented) ~ romans ;
   n = m ;
   part++ ;
 }
 return romans ;

} void main() {

 auto test = [1L,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,25,30,40,50,60,69,70,
   80,90,99,100,200,300,400,500,600,666,700,800,900,1000,1009,1444,1666,1945,1997, 1999,
   2000,2008,2500,3000,4000,4999,5000,6666,10000,50000,100000,500000,1000000,long.max] ;
 foreach(x ; test)   
   writefln("%20s - %s", x, toRoman(x)) ;

}</lang>

Factor

A roman numeral library ships with Factor.

USE: roman
( scratchpad ) 3333 >roman .
"mmmcccxxxiii"
: roman-digits ( -- seq )
    { "m" "cm" "d" "cd" "c" "xc" "l" "xl" "x" "ix" "v" "iv" "i" } ;

: roman-values ( -- seq )
    { 1000 900 500 400 100 90 50 40 10 9 5 4 1 } ;

ERROR: roman-range-error n ;

: roman-range-check ( n -- )
    dup 1 3999 between? [ drop ] [ roman-range-error ] if ;

: (>roman) ( n -- )
    roman-values roman-digits [
        [ /mod swap ] dip <repetition> concat %
    ] 2each drop ;

: >roman ( n -- str )
    dup roman-range-check [ (>roman) ] "" make ;

Fan

<lang Fan>

    • converts a number to its roman numeral representation

class RomanNumerals {

 private Str digit(Str x, Str y, Str z, Int i)
 {
   switch (i)
   {
     case 1: return x
     case 2: return x+x
     case 3: return x+x+x
     case 4: return x+y
     case 5: return y
     case 6: return y+x
     case 7: return y+x+x
     case 8: return y+x+x+x
     case 9: return x+z
   }
   return ""
 }
 Str toRoman(Int i)
 {
   if (i>=1000) { return "M" + toRoman(i-1000) }
   if (i>=100) { return digit("C", "D", "M", i/100) + toRoman(i%100) }
   if (i>=10) { return digit("X", "L", "C", i/10) + toRoman(i%10) }
   if (i>=1) { return digit("I", "V", "X", i) }
   return ""
 }
 Void main()
 {
   2000.times |i| { echo("$i = ${toRoman(i)}") }
 }

} </lang>

Forth

: vector create ( n -- ) 0 do , loop
         does>  ( n -- ) swap cells + @ execute ;

\ these are ( numerals -- numerals )
: .I  dup     c@ emit ;
: .V  dup 1 + c@ emit ;
: .X  dup 2 + c@ emit ;

\ these are ( numerals -- )
:noname  .I .X       drop ;
:noname  .V .I .I .I drop ;
:noname  .V .I .I    drop ;
:noname  .V .I       drop ;
:noname  .V          drop ;
:noname  .I .V       drop ;
:noname  .I .I .I    drop ;
:noname  .I .I       drop ;
:noname  .I          drop ;
                   ' drop \ 0: no output
10 vector .digit

: roman-rec ( numerals n -- )
  10 /mod dup if >r over 2 + r> recurse else drop then .digit ;

: .roman ( n -- )
  dup 0 4000 within 0= if ." EX LIMITO!" exit then
  s" IVXLCDM" drop swap roman-rec ;

Fortran

Works with: Fortran version 90+

<lang fortran> MODULE Roman

IMPLICIT NONE
CONTAINS 
FUNCTION numerals(number)
  CHARACTER(15) :: numerals
  CHARACTER(4) :: thousand_str, hundred_str, ten_str, unit_str
  INTEGER :: number, thousands, hundreds, tens

  thousands = number / 1000
  SELECT CASE (thousands)
    CASE(0)
      thousand_str = ""
    CASE(1:4)
      thousand_str = REPEAT(STRING="M", NCOPIES=thousands)
  END SELECT

  number = MOD(number, 1000)
  hundreds = number / 100

  SELECT CASE (hundreds)
    CASE(0)
      hundred_str = ""	
    CASE(1:3)
      hundred_str = REPEAT(STRING="C", NCOPIES=hundreds)
    CASE(4)
      hundred_str = "CD"
    CASE(5)
      hundred_str = "D"
    CASE(6:8)
      hundred_str = "D"//REPEAT(STRING="C", NCOPIES=hundreds-5)
    CASE(9)
      hundred_str = "CM"
  END SELECT

  number = MOD(number, 100)
  tens = number / 10

  SELECT CASE (tens)
    CASE(0)
      ten_str = ""	
    CASE(1:3)
      ten_str = REPEAT(STRING="X", NCOPIES=tens)
    CASE(4)
      ten_str = "XL"
    CASE(5)
      ten_str = "L"
    CASE(6:8)
      ten_str = "L"//REPEAT(STRING="X", NCOPIES=tens-5)
    CASE(9)
      ten_str = "XC"
  END SELECT

  number = MOD(number, 10)
 
  SELECT CASE (number)
    CASE(0)
      unit_str = ""	
    CASE(1:3)
      unit_str = REPEAT(STRING="I", NCOPIES=number)
    CASE(4)
      unit_str = "IV"
    CASE(5)
      unit_str = "V"
    CASE(6:8)
      unit_str = "V"//REPEAT(STRING="I", NCOPIES=number-5)
    CASE(9)
      unit_str = "IX"
  END SELECT

  numerals = TRIM(thousand_str)//TRIM(hundred_str)//TRIM(ten_str)//TRIM(unit_str)

END FUNCTION
END MODULE

PROGRAM ROMAN_TEST
USE Roman
 
  WRITE(*,*) numerals(2008)
  WRITE(*,*) numerals(1666)
  WRITE(*,*) numerals(3888)

END PROGRAM ROMAN_TEST</lang>

Output

MMVIII
MDCLXVI
MMMDCCCLXXXVIII

Haskell

With an explicit decimal digit representation list:

digit x y z k = 
  [[x],[x,x],[x,x,x],[x,y],[y],[y,x],[y,x,x],[y,x,x,x],[x,z]] !! 
  (fromInteger k - 1)

toRoman :: Integer -> String
toRoman 0 = ""
toRoman x | x < 0     = error "Negative roman numeral"
toRoman x | x >= 1000 = 'M' : toRoman (x - 1000)
toRoman x | x >= 100  = digit 'C' 'D' 'M' q ++ toRoman r where 
  (q,r) = x `divMod` 100
toRoman x | x >= 10   = digit 'X' 'L' 'C' q ++ toRoman r where 
  (q,r) = x `divMod` 10
toRoman x             = digit 'I' 'V' 'X' x

Output:

*Main> map toRoman [1999,25,944]
["MCMXCIX","XXV","CMXLIV"]

J

rfd obtains Roman numerals from decimals, and dfr decimals from Roman numerals.

dfr=: 3 : 0
 i=. 'IVXLCDM' i. y
 d=. i{1 5 10 50 100 500 1000
 +/d*_1^i<}.i,_1
)

r100 =. <;._1 '  C CC CCC CD D DC DCC DCCC CM'
r10  =. <;._1 '  X XX XXX XL L LX LXX LXXX XC'
r1   =. <;._1 '  I II III IV V VI VII VIII IX'
R1000=: , r100 ,&.>/ r10 ,&.>/ r1

rfd=: 3 : 0
 ('M'$~<.y%1000),R1000{::~1000|y
)

Copied, with permission, from the J Wiki. Examples of use will be found there.

Java

Translation of: Ada

The helper function copies is added since Java does not support String multiplication. The conversion function returns null for a negative number, since Java does not have unsigned primitives. <lang java>public class RN{ public static void main(String args[]){ System.out.println(roman(1999)); System.out.println(roman(25)); System.out.println(roman(954)); } public static String roman(long n){ if(n < 1) return null; String result = ""; if(n >= 1000){ result+= (copies("M",(n / 1000))); n%= 1000; } if(n >= 900){ result+= "CM"; n%= 900; } if(n >= 500){ result+= "D"; n%= 500; } if(n >= 400){ result+= "CD"; n%= 400; } if(n >= 100){ result+= (copies("C",(n / 100))); n%= 100; } if(n >= 90){ result+= "XC"; n%= 90; } if(n >= 50){ result+= "L"; n%= 50; } if(n >= 40){ result+= "XL"; n%= 40; } if(n >= 10){ result+= (copies("X",(n / 10))); n%= 10; } if(n == 9){ result+= "IX"; n= 0; } if(n >= 5){ result+= "V"; n%= 5; } if(n == 4){ result+= "IV"; n= 0; } result+= (copies("I",n)); return result; }

public static String copies(String a, int n){ String result = ""; for(int i= 0;i < n;i++,result+= a); return result; } }</lang> Output:

MCMXCIX
XXV
CMXLIV

LaTeX

The macro \Roman is defined for uppercase roman numeral, accepting as argument a name of an existing counter.

<lang latex>\documentclass{article} \begin{document} \newcounter{currentyear}\setcounter{currentyear}{\year} Anno Domini \Roman{currentyear} \end{document}</lang>

Works with: UCB Logo
make "patterns [[?] [? ?] [? ? ?] [? ?2] [?2] [?2 ?] [?2 ? ?] [?2 ? ? ?] [? ?3]]

to digit :d :numerals
  if :d = 0 [output "||]
  output apply (sentence "\( "word (item :d :patterns) "\)) :numerals
end
to digits :n :numerals
  output word ifelse :n < 10 ["||] [digits int :n/10 bf bf :numerals] ~
              digit modulo :n 10 :numerals
end
to roman :n
  if or :n < 0 :n >= 4000 [output [EX MODVS!]]
  output digits :n [I V X L C D M]
end
print roman 1999  ; MCMXCIX 
print roman 25    ; XXV
print roman 944   ; CMXLIV

OCaml

With an explicit decimal digit representation list:

<lang ocaml> let digit x y z = function

   1 -> [x]
 | 2 -> [x;x]
 | 3 -> [x;x;x]
 | 4 -> [x;y]
 | 5 -> [y]
 | 6 -> [y;x]
 | 7 -> [y;x;x]
 | 8 -> [y;x;x;x]
 | 9 -> [x;z]

let rec to_roman x =

 if x = 0 then []
 else if x < 0 then
   invalid_arg "Negative roman numeral"
 else if x >= 1000 then
   'M' :: to_roman (x - 1000)
 else if x >= 100 then
   digit 'C' 'D' 'M' (x / 100) @ to_roman (x mod 100)
 else if x >= 10 then
   digit 'X' 'L' 'C' (x / 10) @ to_roman (x mod 10)
 else
   digit 'I' 'V' 'X' x

</lang>

Output:

# to_roman 1999;;
- : char list = ['M'; 'C'; 'M'; 'X'; 'C'; 'I'; 'X']
# to_roman 25;;
- : char list = ['X'; 'X'; 'V']
# to_roman 944;;
- : char list = ['C'; 'M'; 'X'; 'L'; 'I'; 'V']

Perl

Works with: Romana::Perligata

Perligata outputs numbers in Arabic, but the verb come ("beautify") may be used to convert numbers to proper Roman numerals:

       per quisque in I tum C conscribementum sic
               hoc tum duos multiplicamentum comementum egresso scribe.
       cis

Plain TeX

TeX has its own way to convert a number into roman numeral, but it produces lowercase letters; the following macro (and usage example), produce uppercase roman numeral.

<lang tex>\def\upperroman#1{\uppercase\expandafter{\romannumeral#1}} Anno Domini \upperroman{\year} \bye</lang>


Python

<lang python>roman = "MDCLXVmdclxvi"; # UPPERCASE for thousands # adjust_roman = "CCXXmmccxxii"; arabic = (1000000, 500000, 100000, 50000, 10000, 5000, 1000, 500, 100, 50, 10, 5, 1); adjust_arabic = (100000, 100000, 10000, 10000, 1000, 1000, 100, 100, 10, 10, 1, 1, 0);

def arabic_to_roman(dclxvi):

 org = dclxvi; # 666 #
 out = "";
 for scale,arabic_scale  in enumerate(arabic): 
   if org == 0: break
   multiples = org / arabic_scale;
   org -= arabic_scale * multiples;
   out += roman[scale] * multiples;
   if org >= -adjust_arabic[scale] + arabic_scale: 
     org -= -adjust_arabic[scale] + arabic_scale;
     out +=  adjust_roman[scale] +  roman[scale]
 return out

if __name__ == "__main__":

 test = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,25,30,40,50,60,69,70,
    80,90,99,100,200,300,400,500,600,666,700,800,900,1000,1009,1444,1666,1945,1997,1999,
    2000,2008,2500,3000,4000,4999,5000,6666,10000,50000,100000,500000,1000000);
 for val in test: 
   print '%d - %s'%(val, arabic_to_roman(val))

</lang> An alternative which uses the divmod() function <lang python>romanDgts= 'ivxlcdmVXLCDM_'

def ToRoman(num):

  namoR = 
  if num >=4000000:
     print 'Too Big -'
     return '-----'
  for rdix in range(0, len(romanDgts), 2):
     if num==0: break
     num,r = divmod(num,10)
     v,r = divmod(r, 5)
     if r==4:
        namoR += romanDgts[rdix+1+v] + romanDgts[rdix]
     else:
        namoR += r*romanDgts[rdix] + (romanDgts[rdix+1] if(v==1) else )
  return namoR[-1::-1]</lang>

Ruby

Roman numeral generation was used as an example for demonstrating Test Driven Development in Ruby.

Tcl

<lang tcl>proc to_roman {i} {

   set map {1000 M 900 CM 500 D 400 CD 100 C 90 XC 50 L 40 XL 10 X 9 IX 5 V 4 IV 1 I}
   foreach {value roman} $map {
       while {$i >= $value} {
           append res $roman
           incr i -$value
       }
   }
   return $res

}</lang>