Roman numerals/Encode: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 744: Line 744:
:noname .I .X drop ; :noname .V .I .I .I drop ; :noname .V .I .I drop ;
: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 .V .I drop ; :noname .V drop ; :noname .I .V drop ;
:noname .I .I .I drop ; :noname .I .I drop ; :noname .I drop ;
:noname .I .I .I drop ; :noname .I .I drop ; :noname .I drop ;
' drop ( 0 : no output ) 10 vector .digit
' drop ( 0 : no output ) 10 vector .digit

Revision as of 15:15, 12 October 2010

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.

ActionScript

<lang ActionScript>function arabic2roman(num:Number):String { var lookup:Object = {M:1000, CM:900, D:500, CD:400, C:100, XC:90, L:50, XL:40, X:10, IX:9, V:5, IV:4, I:1}; var roman:String = "", i:String; for (i in lookup) { while (num >= lookup[i]) { roman += i; num -= lookup[i]; } } return roman; } trace("1990 in roman is " + arabic2roman(1990)); trace("2008 in roman is " + arabic2roman(2008)); trace("1666 in roman is " + arabic2roman(1666)); </lang> Output:

1990 in roman is MCMXC
2008 in roman is MMVIII
1666 in roman is MDCLXVI

And the reverse: <lang ActionScript>function roman2arabic(roman:String):Number { var romanArr:Array = roman.toUpperCase().split(); var lookup:Object = {I:1, V:5, X:10, L:50, C:100, D:500, M:1000}; var num:Number = 0, val:Number = 0; while (romanArr.length) { val = lookup[romanArr.shift()]; num += val * (val < lookup[romanArr[0]] ? -1 : 1); } return num; } trace("MCMXC in arabic is " + roman2arabic("MCMXC")); trace("MMVIII in arabic is " + roman2arabic("MMVIII")); trace("MDCLXVI in arabic is " + roman2arabic("MDCLXVI"));</lang> Output:

MCMXC in arabic is 1990
MMVIII in arabic is 2008
MDCLXVI in arabic is 1666

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 Revision 1 - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8-8d

<lang algol68>[]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 (last example is manually wrapped):

         +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 - MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
              MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMCDLXXXmmmdcxlvii

ALGOL W

Works with: awtoc version any - tested with release Mon Apr 27 14:25:27 NZST 2009

<lang algolw>BEGIN

PROCEDURE ROMAN (INTEGER VALUE NUMBER; STRING(15) RESULT CHARACTERS; INTEGER RESULT LENGTH);

   COMMENT
        Returns the Roman number of an integer between 1 and 3999.
        "MMMDCCCLXXXVIII" (15 characters long) is the longest Roman number under 4000;
   BEGIN
       INTEGER PLACE, POWER;
       PROCEDURE APPEND (STRING(1) VALUE C);
           BEGIN CHARACTERS(LENGTH|1) := C; LENGTH := LENGTH + 1 END;
       PROCEDURE I; APPEND(CASE PLACE OF ("I","X","C","M"));
       PROCEDURE V; APPEND(CASE PLACE OF ("V","L","D"));
       PROCEDURE X; APPEND(CASE PLACE OF ("X","C","M"));
       ASSERT (NUMBER >= 1) AND (NUMBER < 4000);
       CHARACTERS := "               ";  
       LENGTH := 0;
       POWER := 1000;  
       PLACE := 4;
       WHILE PLACE > 0 DO
           BEGIN
               CASE NUMBER DIV POWER + 1 OF BEGIN
                   BEGIN            END;
                   BEGIN I          END;
                   BEGIN I; I       END;
                   BEGIN I; I; I    END;
                   BEGIN I; V       END;
                   BEGIN V          END;
                   BEGIN V; I       END;
                   BEGIN V; I; I    END;
                   BEGIN V; I; I; I END;
                   BEGIN I; X       END
               END;
               NUMBER := NUMBER REM POWER;
               POWER := POWER DIV 10;
               PLACE := PLACE - 1
           END
   END ROMAN;

INTEGER I; STRING(15) S;

ROMAN(1, S, I); WRITE(S, I); ROMAN(3999, S, I); WRITE(S, I); ROMAN(3888, S, I); WRITE(S, I); ROMAN(2009, S, I); WRITE(S, I); ROMAN(405, S, I); WRITE(S, I); END.</lang> Output:

I                           1
MMMCMXCIX                   9
MMMDCCCLXXXVIII            15
MMIX                        4
CDV                         3

AutoHotkey

Translated from C++ example <lang AutoHotkey>MsgBox % stor(444)

stor(value) {

 romans = M,CM,D,CD,C,XC,L,XL,X,IX,V,IV,I
 M := 1000
 CM := 900
 D := 500
 CD := 400
 C := 100
 XC := 90
 L := 50
 XL := 40
 X := 10
 IX := 9
 V := 5
 IV := 4
 I := 1
 Loop, Parse, romans, `,
 {
   While, value >= %A_LoopField%
   {
     result .= A_LoopField
     value := value - (%A_LoopField%)
   }
 }
 Return result . "O" 

}</lang>

AWK

Some lines in this example are too long (more than 80 characters). Please fix the code if it's possible and remove this message.
Translation of: Tcl

To cram this into an AWK one-liner is a bit of a stretch, but here goes: <lang awk>$ awk 'func u(v,n){while(i>=v){r=r n;i-=v}}{i=$1;r="";u(1000,"M");u(900,"CM");u(500,"D");u(400,"CD");u(100,"C");u(90,"XC");u(50,"L");u(40,"XL");u(10,"X");u(9,"IX");u(5,"V");u(4,"IV");u(1,"I");print r}' 2009 MMIX 1999 MCMXCIX</lang>

BASIC

Works with: FreeBASIC

<lang freebasic> DIM SHARED arabic(0 TO 12) AS Integer => {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 } DIM SHARED roman(0 TO 12) AS String*2 => {"M", "CM", "D","CD", "C","XC","L","XL","X","IX","V","IV","I"}

FUNCTION toRoman(value AS Integer) AS String

   DIM i 	AS Integer
   DIM result  AS String
   
   FOR i = 0 TO 12
       DO WHILE value >= arabic(i)

result = result + roman(i) value = value - arabic(i) LOOP

   NEXT i
   toRoman = result

END FUNCTION

'Testing PRINT "2009 = "; toRoman(2009) PRINT "1666 = "; toRoman(1666) PRINT "3888 = "; toRoman(3888) </lang>

Output

2009 = MMIX
1666 = MDCLXVI
3888 = MMMDCCCLXXXVIII

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

C#

<lang csharp>using System; class Program {

   static uint[] nums = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
   static string[] rum = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
   static string ToRoman(uint number)
   {
       string value = "";
       for (int i = 0; i < nums.Length && number != 0; i++)
       {
           while (number >= nums[i])
           {
               number -= nums[i];
               value += rum[i];
           }
       }
       return value;
   }
   static void Main()
   {
       for (uint number = 1; number <= 1 << 10; number *= 2)
       {
           Console.WriteLine("{0} = {1}", number, ToRoman(number));
       }
   }

}</lang>

Output:

1 = I
2 = II
4 = IV
8 = VIII
16 = XVI
32 = XXXII
64 = LXIV
128 = CXXVIII
256 = CCLVI
512 = DXII
1024 = MXXIV

C++

<lang cpp>#include <iostream>

  1. include <string>

std::string to_roman(int value) {

 struct romandata_t { int value; char const* numeral; };
 static romandata_t const romandata[] =
    { 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",
         0, 0 }; // end marker
 std::string result;
 for (romandata_t const* current = romandata; current->value > 0; ++current)
 {
   while (value >= current->value)
   {
     result += current->numeral;
     value  -= current->value;
   }
 }
 return result;

}

int main() {

 for (int i = 1; i <= 4000; ++i)
 {
   std::cout << to_roman(i) << std::endl;
 }

}</lang>

Common Lisp

<lang lisp>(defun roman-numeral (n)

 (format nil "~@R" n))</lang>

Clojure

<lang Clojure> (def arabic-roman-map

    {1 "I", 5 "V", 
     10 "X", 50 "L", 
     100 "C", 500 "D", 
     1000 "M", 
     4 "IV", 9 "IX", 
     40 "XL", 90 "XC", 
     400 "CD", 900 "CM" })

(def arabic-roman-map-sorted-keys

    (sort (keys arabic-roman-map)))

(defn find-value-in-coll

 [coll k]
 (let [aval (find coll k)]
 (if (nil? aval) "" (val aval))))

(defn to-roman

 [result n]
 (let
     [closest-key-for-n (last (filter #(> n %) arabic-roman-map-sorted-keys))
      roman-value-for-n (find-value-in-coll arabic-roman-map n)
      roman-value-for-closet-to-n (find-value-in-coll arabic-roman-map

closest-key-for-n)]

      (if (or (<= n 0)(contains? arabic-roman-map n))

(conj result roman-value-for-n) (recur (conj result roman-value-for-closet-to-n) (- n closest-key-for-n)))))

Usage: >(to-roman [] 1999) result: ["M" "CM" "XC" "IX"]

</lang>

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>

Erlang

Translation of: OCaml

<lang erlang>-module(roman). -export([to_roman/1]).

to_roman(0) -> []; to_roman(X) when X >= 1000 -> [$M | to_roman(X - 1000)]; to_roman(X) when X >= 100 ->

   digit(X div 100, $C, $D, $M) ++ to_roman(X rem 100);

to_roman(X) when X >= 10 ->

   digit(X div 10, $X, $L, $C) ++ to_roman(X rem 10);

to_roman(X) when X >= 1 -> digit(X, $I, $V, $X).

digit(1, X, _, _) -> [X]; digit(2, X, _, _) -> [X, X]; digit(3, X, _, _) -> [X, X, X]; digit(4, X, Y, _) -> [X, Y]; digit(5, _, Y, _) -> [Y]; digit(6, X, Y, _) -> [Y, X]; digit(7, X, Y, _) -> [Y, X, X]; digit(8, X, Y, _) -> [Y, X, X, X]; digit(9, X, _, Z) -> [X, Z].</lang>

sample:

1> c(roman).            
{ok,roman}
2> roman:to_roman(1999).
"MCMXCIX"
3> roman:to_roman(25).  
"XXV"
4> roman:to_roman(944).
"CMXLIV"

Factor

A roman numeral library ships with Factor. <lang factor>USE: roman ( scratchpad ) 3333 >roman . "mmmcccxxxiii"</lang>

Parts of the implementation:

<lang factor>CONSTANT: roman-digits

   { "m" "cm" "d" "cd" "c" "xc" "l" "xl" "x" "ix" "v" "iv" "i" }

CONSTANT: roman-values

   { 1000 900 500 400 100 90 50 40 10 9 5 4 1 }

ERROR: roman-range-error n ;

roman-range-check ( n -- n )
   dup 1 10000 between? [ roman-range-error ] unless ;
>roman ( n -- str )
   roman-range-check
   roman-values roman-digits [
       [ /mod swap ] dip <repetition> concat
   ] 2map "" concat-as nip ;</lang>

FALSE

<lang false>^$." " [$999>][1000- "M"]#

$899> [ 900-"CM"]?
$499> [ 500- "D"]?
$399> [ 400-"CD"]?

[$ 99>][ 100- "C"]#

$ 89> [  90-"XC"]?
$ 49> [  50- "L"]?
$ 39> [  40-"XL"]?

[$ 9>][ 10- "X"]#

$  8> [   9-"IX"]?
$  4> [   5- "V"]?
$  3> [   4-"IV"]?

[$ ][ 1- "I"]#%</lang>

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

<lang forth>: vector create ( n -- ) 0 do , loop does> ( n -- ) swap cells + @ execute ; \ these are ( numerals -- numerals )

.I dup c@ C, ;  : .V dup 1 + c@ C, ;  : .X dup 2 + c@ C, ;

\ 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 -- c-addr u )
 dup 0 4000 within 0= if ." EX LIMITO!" exit then  
 HERE SWAP  s" IVXLCDM" drop swap roman-rec  HERE OVER - ;</lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>program roman_numerals

 implicit none
 write (*, '(a)') roman (2009)
 write (*, '(a)') roman (1666)
 write (*, '(a)') roman (3888)

contains

function roman (n) result (r)

 implicit none
 integer, intent (in) :: n
 integer, parameter   :: d_max = 13
 integer              :: d
 integer              :: m
 integer              :: m_div
 character (32)       :: r
 integer,        dimension (d_max), parameter :: d_dec = &
   & (/1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1/)
 character (32), dimension (d_max), parameter :: d_rom = &
   & (/'M ', 'CM', 'D ', 'CD', 'C ', 'XC', 'L ', 'XL', 'X ', 'IX', 'V ', 'IV', 'I '/)
 r = 
 m = n
 do d = 1, d_max
   m_div = m / d_dec (d)
   r = trim (r) // repeat (trim (d_rom (d)), m_div)
   m = m - d_dec (d) * m_div
 end do

end function roman

end program roman_numerals</lang>

Output:

 MMIX
 MDCLXVI
 MMMDCCCLXXXVIII

Groovy

<lang groovy>symbols = [ 1:'I', 4:'IV', 5:'V', 9:'IX', 10:'X', 40:'XL', 50:'L', 90:'XC', 100:'C', 400:'CD', 500:'D', 900:'CM', 1000:'M' ]

def roman(arabic) {

   def result = ""
   symbols.keySet().sort().reverse().each { 
       while (arabic >= it) {
           arabic-=it
           result+=symbols[it]
       }
   }
   return result

} assert roman(1) == 'I' assert roman(2) == 'II' assert roman(4) == 'IV' assert roman(8) == 'VIII' assert roman(16) == 'XVI' assert roman(32) == 'XXXII' assert roman(25) == 'XXV' assert roman(64) == 'LXIV' assert roman(128) == 'CXXVIII' assert roman(256) == 'CCLVI' assert roman(512) == 'DXII' assert roman(954) == 'CMLIV' assert roman(1024) == 'MXXIV' assert roman(1666) == 'MDCLXVI' assert roman(1990) == 'MCMXC' assert roman(2008) == 'MMVIII'</lang>

Haskell

With an explicit decimal digit representation list:

<lang haskell>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</lang>

Output:

<lang haskell>*Main> map toRoman [1999,25,944] ["MCMXCIX","XXV","CMXLIV"]</lang>

HicEst

<lang hicest>CHARACTER Roman*20

CALL RomanNumeral(1990, Roman) ! MCMXC CALL RomanNumeral(2008, Roman) ! MMVIII CALL RomanNumeral(1666, Roman) ! MDCLXVI

END

SUBROUTINE RomanNumeral( arabic, roman)

 CHARACTER roman
 DIMENSION ddec(13)
 DATA      ddec/1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1/
 roman = ' '
 todo = arabic
 DO d = 1, 13
   DO rep = 1, todo / ddec(d)
     roman = TRIM(roman) // TRIM(CHAR(d, 13, "M  CM D  CD C  XC L  XL X  OX V  IV I  "))
     todo = todo - ddec(d)
   ENDDO
 ENDDO

END</lang>

Icon and Unicon

Icon

<lang Icon>link numbers # commas, roman

procedure main(arglist) every x := !arglist do

  write(commas(x), " -> ",roman(x)|"*** can't convert to Roman numerals ***")

end</lang>

fib provides numbers:roman as seen below and based on a James Gimple SNOBOL4 function.

<lang Icon>procedure roman(n) #: convert integer to Roman numeral

  local arabic, result
  static equiv
  initial equiv := ["","I","II","III","IV","V","VI","VII","VIII","IX"]
  integer(n) > 0 | fail
  result := ""
  every arabic := !n do
     result := map(result,"IVXLCDM","XLCDM**") || equiv[arabic + 1]
  if find("*",result) then fail else return result

end</lang>

Sample output:

#roman.exe  3 4 8 49 2010 1666 3000 3999 4000 

3 -> III
4 -> IV
8 -> VIII
49 -> XLIX
2,010 -> MMX
1,666 -> MDCLXVI
3,999 -> MMMCMXCIX
4,000 -> *** can't convert to Roman numerals ***

Unicon

This Icon solution works in Unicon.

Io

Translation of: C#

<lang Io>Roman := Object clone do (

   nums := list(1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
   rum := list("M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I")
   
   numeral := method(number,
       result := ""
       for(i, 0, nums size,
           if(number == 0, break)
           while(number >= nums at(i),
               number = number - nums at(i)
               result = result .. rum at(i)
           )
       )
       return result
   )

)

Roman numeral(1666) println</lang>

J

rfd obtains Roman numerals from decimals.

<lang j>R1000=. ;L:1 ,{ <@(<;._1);._2]0 :0

 C CC CCC CD D DC DCC DCCC CM
 X XX XXX XL L LX LXX LXXX XC
 I II III IV V VI VII VIII IX

)

rfd=: ('M' $~ <.@%&1000) , R1000 {::~ 1000&|</lang>

For example:<lang j> rfd 1234 MCCXXXIV

  rfd 567

DLXVII

  rfd 89

LXXXIX</lang>

Derived from the J Wiki. Further 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 non-positive numbers, 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

JavaScript

Translation of: Tcl

<lang javascript>var roman = {

   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',
   ],
   int_to_roman: function(n) {
       var value = ;
       for (var idx = 0; n > 0 && idx < this.map.length; idx += 2) {
           while (n >= this.map[idx]) {
               value += this.map[idx + 1];
               n -= this.map[idx];
           }
       }
       return value;
   }

}

roman.int_to_roman(1999); // "MCMXCIX"</lang>

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>

<lang logo>make "roman.rules [

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

]

to roman :n [:rules :roman.rules] [:acc "||]

 if empty? :rules [output :acc]
 if :n < first first :rules [output (roman :n bf :rules :acc)]
 output (roman :n - first first :rules  :rules  word :acc last first :rules)

end</lang>

Works with: UCB Logo

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

LotusScript

<lang lss> Function toRoman(value) As String Dim arabic(12) As Integer Dim roman(12) As String

arabic(0) = 1000 arabic(1) = 900 arabic(2) = 500 arabic(3) = 400 arabic(4) = 100 arabic(5) = 90 arabic(6) = 50 arabic(7) = 40 arabic(8) = 10 arabic(9) = 9 arabic(10) = 5 arabic(11) = 4 arabic(12) = 1

roman(0) = "M" roman(1) = "CM" roman(2) = "D" roman(3) = "CD" roman(4) = "C" roman(5) = "XC" roman(6) = "L" roman(7) = "XL" roman(8) = "X" roman(9) = "IX" roman(10) = "V" roman(11) = "IV" roman(12) = "I"

Dim i As Integer, result As String

For i = 0 To 12 Do While value >= arabic(i) result = result + roman(i) value = value - arabic(i) Loop Next i

toRoman = result End Function

</lang>

Lua

<lang lua>romans = { {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"} }

k = io.read() + 0 for _, v in ipairs(romans) do --note that this is -not- ipairs.

 val, let = unpack(v)
 while k >= val do
   k = k - val

io.write(let)

 end

end print()</lang>

M4

<lang M4>define(`roman',`ifelse(eval($1>=1000),1,`M`'roman(eval($1-1000))', `ifelse(eval($1>=900),1,`CM`'roman(eval($1-900))', `ifelse(eval($1>=500),1,`D`'roman(eval($1-500))', `ifelse(eval($1>=100),1,`C`'roman(eval($1-100))', `ifelse(eval($1>=90),1,`XC`'roman(eval($1-90))', `ifelse(eval($1>=50),1,`L`'roman(eval($1-50))', `ifelse(eval($1>=40),1,`XL`'roman(eval($1-40))', `ifelse(eval($1>=10),1,`X`'roman(eval($1-10))', `ifelse(eval($1>=9),1,`IX`'roman(eval($1-9))', `ifelse(eval($1>=5),1,`V`'roman(eval($1-5))', `ifelse(eval($1>=4),1,`IV`'roman(eval($1-4))', `ifelse(eval($1>=1),1,`I`'roman(eval($1-1))' )')')')')')')')')')')')')dnl dnl roman(3675)</lang>

Output:

MMMDCLXXV

Mathematica

Define a custom function that works on positive numbers (RomanForm[0] will not be evaluated): <lang Mathematica>RomanForm[i_Integer?Positive] :=

Module[{num = i, string = "", value, letters, digits}, 
 digits = {{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"}};
 While[num > 0, {value, letters} = 
   Which @@ Flatten[{num >= #1, ##} & /@ digits, 1];
  num -= value;
  string = string <> letters;];
 string]</lang>

Examples: <lang Mathematica>RomanForm[4] RomanForm[99] RomanForm[1337] RomanForm[1666] RomanForm[6889]</lang> gives back: <lang Mathematica>IV XCIX MCCCXXXVII MDCLXVI MMMMMMDCCCLXXXIX</lang>

MUMPS

<lang MUMPS>TOROMAN(INPUT)

;Converts INPUT into a Roman numeral. INPUT must be an integer between 1 and 3999
;OUTPUT is the string to return
;I is a loop variable
;CURRVAL is the current value in the loop
QUIT:($FIND(INPUT,".")>1)!(INPUT<=0)!(INPUT>3999) "Invalid input"
NEW OUTPUT,I,CURRVAL
SET OUTPUT="",CURRVAL=INPUT
SET:$DATA(ROMANNUM)=0 ROMANNUM="I^IV^V^IX^X^XL^L^XC^C^CD^D^CM^M"
SET:$DATA(ROMANVAL)=0 ROMANVAL="1^4^5^9^10^40^50^90^100^400^500^900^1000"
FOR I=$LENGTH(ROMANVAL,"^"):-1:1 DO
.FOR  Q:CURRVAL<$PIECE(ROMANVAL,"^",I)  SET OUTPUT=OUTPUT_$PIECE(ROMANNUM,"^",I),CURRVAL=CURRVAL-$PIECE(ROMANVAL,"^",I)
KILL I,CURRVAL
QUIT OUTPUT</lang>

Output:

USER>W $$ROMAN^ROSETTA(1666)
MDCLXVI
USER>W $$TOROMAN^ROSETTA(2010)
MMX
USER>W $$TOROMAN^ROSETTA(949)
CMXLIX
USER>W $$TOROMAN^ROSETTA(949.24)
Invalid input
USER>W $$TOROMAN^ROSETTA(-949)
Invalid input

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

Oz

Translation of: Haskell

<lang oz>declare

 fun {Digit X Y Z K}
    unit([X] [X X] [X X X] [X Y] [Y] [Y X] [Y X X] [Y X X X] [X Z])
    .K
 end
 fun {ToRoman X}
    if     X == 0    then ""
    elseif X < 0     then raise toRoman(negativeInput X) end
    elseif X >= 1000 then "M"#{ToRoman X-1000}
    elseif X >= 100  then {Digit &C &D &M  X div 100}#{ToRoman X mod 100}
    elseif X >= 10   then {Digit &X &L &C  X div 10}#{ToRoman X mod 10}
    else                  {Digit &I &V &X  X}
    end
 end

in

 {ForAll {Map [1999 25 944] ToRoman} System.showInfo}</lang>

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:

<lang perl>per quisque in I tum C conscribementum sic

       hoc tum duos multiplicamentum comementum egresso scribe.

cis</lang>

Perl 6

<lang perl6>my %symbols =

   1 => "I", 5 => "V", 10 => "X", 50 => "L", 100 => "C",
   500 => "D", 1_000 => "M";

my @subtractors =

   1_000, 100,  500, 100,  100, 10,  50, 10,  10, 1,  5, 1,  1, 0;

sub roman (Int $n where { $n > 0 }) {

   return %symbols{$n} if %symbols{$n};
   for @subtractors -> $cut, $minus {
       $cut < $n
           and return %symbols{$cut} ~ roman($n - $cut);
       $cut - $minus <= $n
           and return %symbols{$minus} ~ roman($n + $minus);
    }

}</lang>

Sample usage

<lang perl6>for 1 .. 2_010 -> $x {

   say roman($x);

}</lang>

PHP

Works with: PHP version 4+ tested in 5.2.12

<lang php> /**

* int2roman
* Convert any positive value of a 32-bit signed integer to its modern roman 
* numeral representation. Numerals within parentheses are multiplied by 
* 1000. ie. M == 1 000, (M) == 1 000 000, ((M)) == 1 000 000 000
* 
* @param number - an integer between 1 and 2147483647
* @return roman numeral representation of number
*/

function int2roman($number) { if (!is_int($number) || $number < 1) return false; // ignore negative numbers and zero

$integers = array(900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1); $numerals = array('CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'); $major = intval($number / 1000) * 1000; $minor = $number - $major; $numeral = $leastSig = ;

for ($i = 0; $i < sizeof($integers); $i++) { while ($minor >= $integers[$i]) { $leastSig .= $numerals[$i]; $minor -= $integers[$i]; } }

if ($number >= 1000 && $number < 40000) { if ($major >= 10000) { $numeral .= '('; while ($major >= 10000) { $numeral .= 'X'; $major -= 10000; } $numeral .= ')'; } if ($major == 9000) { $numeral .= 'M(X)'; return $numeral . $leastSig; } if ($major == 4000) { $numeral .= 'M(V)'; return $numeral . $leastSig; } if ($major >= 5000) { $numeral .= '(V)'; $major -= 5000; } while ($major >= 1000) { $numeral .= 'M'; $major -= 1000; } }

if ($number >= 40000) { $major = $major/1000; $numeral .= '(' . int2roman($major) . ')'; }

return $numeral . $leastSig; } </lang>

PicoLisp

<lang PicoLisp>(de roman (N)

  (pack
     (make
        (mapc
           '((C D)
              (while (>= N D)
                 (dec 'N D)
                 (link C) ) )
           '(M CM D CD C XC L XL X IX V IV I)
           (1000 900 500 400 100 90 50 40 10 9 5 4 1) ) ) ) )</lang>

Output:

: (roman 1009)
-> "MIX"

: (roman 1666)
-> "MDCLXVI"

Pike

<lang pike>import String; int main(){

  write(int2roman(2009) + "\n");
  write(int2roman(1666) + "\n");
  write(int2roman(1337) + "\n");

}</lang>

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>

PL/I

<lang PL/I> /* From Wiki Fortran */ roman: procedure (n) returns(character (32) varying);

  declare n fixed binary nonassignable;
  declare (d, m) fixed binary;
  declare (r, m_div) character (32) varying;
  declare d_dec(13) fixed binary static initial
     (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1);
  declare d_rom(13) character (2) varying static initial
     ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L',
      'XL', 'X', 'IX', 'V', 'IV', 'I');
  r = ;
  m = n;
  do d = 1 to 13;
     m_div = m / d_dec (d);
     r = r || copy (d_rom (d), m_div);
     m = m - d_dec (d) * m_div;
  end;
  return (r);

end roman; </lang>

PowerBASIC

Translation of: BASIC
Works with: PB/Win version 8+
Works with: PB/CC version 5

<lang powerbasic>FUNCTION toRoman(value AS INTEGER) AS STRING

   DIM arabic(0 TO 12) AS INTEGER
   DIM roman(0 TO 12) AS STRING
   ARRAY ASSIGN arabic() = 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1
   ARRAY ASSIGN roman() = "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"
   DIM i AS INTEGER
   DIM result AS STRING
   FOR i = 0 TO 12
       DO WHILE value >= arabic(i)
           result = result & roman(i)
           value = value - arabic(i)
       LOOP
   NEXT i
   toRoman = result

END FUNCTION

FUNCTION PBMAIN

   'Testing
   ? "2009 = " & toRoman(2009)
   ? "1666 = " & toRoman(1666)
   ? "3888 = " & toRoman(3888)

END FUNCTION</lang>

Protium

Roman numbers are built in to Protium as a particular form of national number. However, for the sake of the task the _RO opcode has been defined. <lang html><@ DEFUDOLITLIT>_RO|__Transformer|<@ DEFKEYPAR>__NationalNumericID|2</@><@ LETRESCS%NNMPAR>...|1</@></@>

<@ ENU$$DLSTLITLIT>1990,2008,1,2,64,124,1666,10001|,| <@ SAYELTLST>...</@> is <@ SAY_ROELTLSTLIT>...|RomanLowerUnicode</@> <@ SAY_ROELTLSTLIT>...|RomanUpperUnicode</@> <@ SAY_ROELTLSTLIT>...|RomanASCII</@> </@></lang>

Same code in padded-out, variable-length English dialect <lang html><# DEFINE USERDEFINEDOPCODE LITERAL LITERAL>_RO|__Transformer|<# DEFINE KEYWORD PARAMETER>__NationalNumericID|2</#><# LET RESULT CAST NATIONALNUMBER PARAMETER>...|1</#></#>

<# ENUMERATION LAMBDASPECIFIEDDELMITER LIST LITERAL LITERAL>1990,2008,1,2,64,124,1666,10001|,| <# SAY ELEMENT LIST>...</#> is <# SAY _RO ELEMENT LIST LITERAL>...|RomanLowerUnicode</#> <# SAY _RO ELEMENT LIST LITERAL>...|RomanUpperUnicode</#> <# SAY _RO ELEMENT LIST LITERAL>...|RomanASCII</#> </#></lang>

Output. Notice here the three different ways of representing the results. For reasons for notational differences, see wp:Roman_numerals#Alternate_forms

1990 is ⅿⅽⅿⅹⅽ ⅯⅭⅯⅩⅭ MCMXC
2008 is ⅿⅿⅷ ⅯⅯⅧ MMVIII
1 is ⅰ Ⅰ I
2 is ⅱ Ⅱ II
64 is ⅼⅹⅳ ⅬⅩⅣ LXIV
124 is ⅽⅹⅹⅳ ⅭⅩⅩⅣ CXXIV
1666 is ⅿⅾⅽⅼⅹⅵ ⅯⅮⅭⅬⅩⅥ MDCLXVI
10001 is ⅿⅿⅿⅿⅿⅿⅿⅿⅿⅿⅰ ↂⅠ MMMMMMMMMMI

PureBasic

<lang PureBasic>#SymbolCount = 12 ;0 based count DataSection

 denominations:
 Data.s "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" ;0-12
 
 denomValues:
 Data.i  1000,900,500,400,100,90,50,40,10,9,5,4,1 ;values in decending sequential order

EndDataSection

-setup

Structure romanNumeral

 symbol.s 
 value.i

EndStructure

Global Dim refRomanNum.romanNumeral(#SymbolCount)

Restore denominations For i = 0 To #SymbolCount

 Read.s refRomanNum(i)\symbol

Next

Restore denomValues For i = 0 To #SymbolCount

 Read refRomanNum(i)\value

Next

Procedure.s decRoman(n)

 ;converts a decimal number to a roman numeral
 Protected roman$, i
 
 For i = 0 To #SymbolCount
   Repeat
     If n >= refRomanNum(i)\value
       roman$ + refRomanNum(i)\symbol
       n - refRomanNum(i)\value
     Else
       Break
     EndIf
   ForEver
 Next
 ProcedureReturn roman$

EndProcedure

If OpenConsole()

 PrintN(decRoman(1999)) ;MCMXCIX
 PrintN(decRoman(1666)) ;MDCLXVI
 PrintN(decRoman(25))   ;XXV
 PrintN(decRoman(954))  ;CMLIV
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit")
 Input()
 CloseConsole()

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

R

R has a built-in function, as.roman, for conversion to roman numerals. The implementation details are found in utils:::.numeric2roman (see previous link), and utils:::.roman2numeric, for conversion back to arabic decimals. <lang R>as.roman(1666) # MDCLXVI</lang>

Retro

This is a port of the Forth code; but returns a string rather than displaying the roman numerals. It only handles numbers between 1 and 3999.

<lang Retro>with buffer'

vector ( ...n"- )
 here [ &, times ] dip : .data ` swap ` + ` @ ` do ` ; ;
.I dup @ addToBuffer ;
.V dup 1 + @ addToBuffer ;
.X dup 2 + @ addToBuffer ;
.I .X drop ;
.V .I .I .I drop ;
.V .I .I drop ;
.V .I drop ;
.V drop ;
.I .V drop ;
.I .I .I drop ;
.I .I drop ;
.I drop ;

&drop 10 vector .digit

record ( an- )
 10 /mod dup if [ over 2 + ] dip record else drop then .digit ;
toRoman ( n-a )
 here setBuffer
 dup 1 3999 within 0 =if "EX LIMITO!\n" puts ;then
 "IVXLCDM" swap record here ;</lang>

REXX

<lang rexx>roman: procedure arg number

/* handle only 1 to 3999, else return ? */ if number >= 4000 | number <= 0 then return "?"

romans = " M CM D CD C XC L XL X IX V IV I" arabic = "1000 900 500 400 100 90 50 40 10 9 5 4 1"

result = "" do i = 1 to words(romans)

 do while number >= word(arabic,i)
   result = result || word(romans,i)
   number = number - word(arabic,i)
 end

end return result</lang>

Ruby

Roman numeral generation was used as an example for demonstrating Test Driven Development in Ruby. The solution came to be: <lang ruby>Symbols = { 1=>'I', 5=>'V', 10=>'X', 50=>'L', 100=>'C', 500=>'D', 1000=>'M' } Subtractors = [ [1000, 100], [500, 100], [100, 10], [50, 10], [10, 1], [5, 1], [1, 0] ]

def roman(num)

 return Symbols[num]  if Symbols.has_key?(num)
 Subtractors.each do |cutPoint, subtractor| 
   return roman(cutPoint) + roman(num - cutPoint)      if num >  cutPoint
   return roman(subtractor) + roman(num + subtractor)  if num >= cutPoint - subtractor and num < cutPoint
 end

end</lang>

Scala

Works with: Scala version 2.8

<lang scala>val romanDigits = Map(

 1 -> "I", 5 -> "V", 
 10 -> "X", 50 -> "L", 
 100 -> "C", 500 -> "D", 
 1000 -> "M", 
 4 -> "IV", 9 -> "IX", 
 40 -> "XL", 90 -> "XC", 
 400 -> "CD", 900 -> "CM")

val romanDigitsKeys = romanDigits.keysIterator.toList sortBy (x => -x) def toRoman(n: Int): String = romanDigitsKeys find (_ >= n) match {

 case Some(key) => romanDigits(key) + toRoman(n - key)
 case None => ""

}</lang>

Sample:

scala> List(1990, 2008, 1666) map toRoman
res55: List[String] = List(MCMXC, MMVIII, MDCLXVI)

Scheme

This uses format directives supported in Chez Scheme since v6.9b; YMMV.

<lang scheme>(define (to-roman n)

 (format "~@r" n))</lang>

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>

SNOBOL4

Adapted from Catspaw SNOBOL Tutorial, Chapter 6

<lang snobol4>

  • ROMAN(N) - Convert integer N to Roman numeral form.
  • N must be positive and less than 4000.
  • An asterisk appears in the result if N >= 4000.
  • The function fails if N is not an integer.

DEFINE('ROMAN(N)UNITS')  :(ROMAN_END)

  • Get rightmost digit to UNITS and remove it from N.
  • Return null result if argument is null.

ROMAN N RPOS(1) LEN(1) . UNITS = :F(RETURN)

  • Search for digit, replace with its Roman form.
  • Return failing if not a digit.

'0,1I,2II,3III,4IV,5V,6VI,7VII,8VIII,9IX,' UNITS + BREAK(',') . UNITS :F(FRETURN)

  • Convert rest of N and multiply by 10. Propagate a
  • failure return from recursive call back to caller.

ROMAN = REPLACE(ROMAN(N), 'IVXLCDM', 'XLCDM**') + UNITS :S(RETURN) F(FRETURN) ROMAN_END

  • Testing

OUTPUT = "1999 = " ROMAN(1999) OUTPUT = " 24 = " ROMAN(24) OUTPUT = " 944 = " ROMAN(944)

END</lang> Outputs:

1999 = MCMXCIX
  24 = XXIV
 944 = CMXLIV

Here's a non-recursive version, and a Roman-to-Arabic converter to boot.

<lang SNOBOL4>* # Arabic to Roman

       define('roman(n)s,ch,val,str') :(roman_end)

roman roman = ge(n,4000) n :s(return)

       s = 'M1000 CM900 D500 CD400 C100 XC90 L50 XL40 X10 IX9 V5 IV4 I1 '

rom1 s span(&ucase) . ch break(' ') . val span(' ') = :f(rom2)

       str = str dupl(ch,(n / val))
       n = remdr(n,val) :(rom1)

rom2 roman = str :(return) roman_end

  • # Roman to Arabic
       define('arabic(n)s,ch,val,sum,x') :(arabic_end)

arabic s = 'M1000 D500 C100 L50 X10 V5 I1 '

       n = reverse(n)

arab1 n len(1) . ch = :f(arab2)

       s ch break(' ') . val
       val = lt(val,x) (-1 * val)
       sum = sum + val; x = val :(arab1)

arab2 arabic = sum :(return) arabic_end

  • # Test and display
       tstr = '2010 1999 1492 1066 476 '

tloop tstr break(' ') . year span(' ') = :f(out)

       r = roman(year)
       rstr = rstr year '=' r ' ' 
       astr = astr r '=' arabic(r) ' ' :(tloop)

out output = rstr; output = astr end</lang>

Output:

2010=MMX 1999=MCMXCIX 1492=MCDXCII 1066=MLXVI 476=CDLXXVI
MMX=2010 MCMXCIX=1999 MCDXCII=1492 MLXVI=1066 CDLXXVI=476

Ursala

The algorithm is to implement the subtractive principle by string substitution only after constucting the numeral from successive remainders. The order among the substitutions matters. For example, occurrences of DCCCC must be replaced by CM before any occurrences of CCCC are replaced by CD. The substitution operator (%=) is helpful here. <lang Ursala>#import nat

roman =

-+

  'IIII'%='IV'+ 'VIIII'%='IX'+ 'XXXX'%='XL'+ 'LXXXX'%='XC'+ 'CCCC'%='CD'+ 'DCCCC'%='CM',
  ~&plrDlSPSL/'MDCLXVI'+ iota*+ +^|(^|C/~&,\/division)@rlX=>~&iNC <1000,500,100,50,10,5>+-</lang>

This test program applies the function to each member of a list of numbers. <lang Ursala>#show+

test = roman* <1990,2008,1,2,64,124,1666,10001></lang> output:

MCMXC
MMVIII
I
II
LXIV
CXXIV
MDCLXVI
MMMMMMMMMMI

Vedit macro language

<lang vedit>do {

   #1 = Get_Num("Number to convert: ")
   Call("ROMAN_NUMBER")
   Reg_Type(1) Message("\n")

} while (Reg_Size(1)) Return

// Convert numeric value into Roman number // #1 = number to convert; on return: T-reg(1) = Roman number //

ROMAN_NUMBER:
   Reg_Empty(1)                        // @1 = Results (Roman number)
   if (#1 < 1) { Return }              // non-positive numbers return empty string
   Buf_Switch(Buf_Free)
   Ins_Text("M1000,CM900,D500,CD400,C100,XC90,L50,XL40,X10,IX9,V5,IV4,I1")
   BOF
   Repeat(ALL) {
       Search("|A|[|A]", ADVANCE+ERRBREAK)         // get next item from conversion list
       Reg_Copy_Block(20, CP-Chars_Matched, CP)    // @20 = Letter(s) to be inserted
       #11 = Num_Eval()                            // #11 = magnitude (1000...1)
       while (#1 >= #11) {
           Reg_Set(1, @20, APPEND)
           #1 -= #11
       }
   }
   Buf_Quit(OK)

Return</lang>

Visual Basic

Translation of: BASIC

<lang vb>Function toRoman(value) As String

   Dim arabic As Variant
   Dim roman As Variant
   arabic = Array(1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
   roman = Array("M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I")
   Dim i As Integer, result As String
   For i = 0 To 12
       Do While value >= arabic(i)
           result = result + roman(i)
           value = value - arabic(i)
       Loop
   Next i
   toRoman = result

End Function

Sub Main()

   MsgBox toRoman(Val(InputBox("Number, please")))

End Sub</lang>