Converting decimal numbers to Roman numerals in JavaScript

Recently I decided to provide all the copyright dates on my sites in Roman numerals rather than decimal, just for something different. It’s not a major change I know, but it was something I wanted to do.

First of all I had to find out how the conversions were actually made. I went to Google, that all important source of information, and found an existing solution written in Java. I quickly converted this to JavaScript, and it is the current script running on the majority of my websites. This simple code is shown below:

var roman = new Array();
roman = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"];
var decimal = new Array();
decimal = [1000,900,500,400,100,90,50,40,10,9,5,4,1];
function decimalToRomanSimple(value) {
  if (value <= 0 || value >= 4000) return value;
    var romanNumeral = "";
    for (var i=0; i<roman.length; i++) {
      while (value >= decimal[i]) { 
        value -= decimal[i];
        romanNumeral += roman[i];
      }
    }
    return romanNumeral;
}

However, it is limited to numbers under 4000, which is fine for years, but what about numbers higher than this?

A quick look at the Wikipedia article on Roman numerals will reveal that numbers in thousands are usually written with a bar over the base numeral, or with rounded brackets placed around it. I prefer the bar method so this is what I am going to implement (as you will see however, changing it to use rounded brackets is very easy).

Both the roman and decimal arrays defined in the sample code above will be re-used. So assume that these have been defined as above. Next, I took the code within the for loop in the above sample and put it into its own function, with some additional information:

function getRoman(value) {
  var romanNumeral = "";
  var numThousands = 0;
  for (var i=0; i<roman.length; i++) {
    if (value == 0) break;	
    while (value >= decimal[i]) {
      value -= decimal[i];
      romanNumeral += roman[i];
      if (roman[i] == 'M') numThousands++;
    }			
  }
  return { numThousands:numThousands, romanNumeral:romanNumeral };
}

As you can see, it now also counts the “number of thousands” i.e. the number of times that an ‘M’ is inserted into the romanNumeral variable. This is then returned in an object with the generated Roman numeral.

I then created the decimalToRoman() function which uses the above function to generate the required numeral:

function decimalToRoman(value) {
  // 3,888,888 is the longest number represented by Roman numerals
  if (value <= 0 || value > 3888888) return value;
  var romanNumeral1 = "";
  var romanO = getRoman(value);
  // If the number is 4000 or greater
  if (romanO.numThousands > 4) {
    var thousandString = "";
    for (var j=0;j<romanO.numThousands;j++) thousandString += "M";
      var thousandsO = getRoman(romanO.numThousands);
      var thBase = "<span style='border-top:1px solid #000'>" + 
thousandsO.romanNumeral + "</span>";
      romanNumeral = romanO.romanNumeral.replace(thousandString, thBase);
    }
    else romanNumeral = romanO.romanNumeral;
    return romanNumeral;
}

This generates the Roman numeral and then checks to see if the number of thousands is 4 or more. If so, it then replaces the “thousand String” (a list of Ms) with the appropriate base number contained in a span with a CSS styled top border of 1px. This is where you can change the top border to use brackets if you so wish, by setting: thBase = "(" + thousandsO.romanNumeral + ")";.

I have created a Roman numeral test page where you can see it in action for yourself.

Any thoughts and comments, as always, greatly appreciated!