From Decimal to Roman

The C language lacks a printf() conversion character to display Roman numerals. Therefore, if your code requires input of a decimal value, say 266, and output of a Roman numeral value, which would be CCLXVI, you must craft your own function.

The process isn’t that difficult, specifically when you don’t care about the reduced values IV, IX, XL, XC, CD, and CM. Forget that those abbreviations exist for a moment and concentrate on the problem: Take a decimal (int) value and peel out the Roman numeral digits in order, highest-to-lowest: M, D, C, L, X, V, and then I.

The code is similar to the solution for the common “make change” programming puzzle. I presented that problem as an Exercise back in December 2014, which is December MMXIIII. Or, if you abbreviate, it’s December MMXIV.

Like the “make change” solution, to convert a decimal value to a Roman numeral string, you subtract high values from the input. Then you subtract smaller values on down, processing the number until it’s whittled to zero.

My code starts with a main() function that obtains input in the range of 1 to 5000. You must ensure that the values are positive and not too big, though you can set any range you like to see how the code handles it.

The decimal2roman() function performs the translation.

#include <stdio.h>

#define SIZE 20

void decimal2roman(char *r,int v);

int main()
{
    char roman[SIZE];
    int value;

    /* get input */
    printf("Type an integer value: ");
    scanf("%d",&value);

    /* test range */
    if(value < 1 || value > 5000)
    {
        puts("Valid input is from 1 through 5000");
        return(1);
    }

    /* translate and display results */
    decimal2roman(roman,value);
    printf("The value %d is %s\n",value,roman);

    return(0);
}

void decimal2roman(char *r,int v)
{
    int index = 0;

    while(v)
    {
        if(v >= 1000)
        {
            *(r+index) = 'M';
            index++;
            v -= 1000;
        }
        else if(v >= 500)
        {
            *(r+index) = 'D';
            index++;
            v -= 500;
        }
        else if(v >= 100)
        {
            *(r+index) = 'C';
            index++;
            v -= 100;
        }
        else if(v >= 50)
        {
            *(r+index) = 'L';
            index++;
            v -= 50;
        }
        else if(v >= 10)
        {
            *(r+index) = 'X';
            index++;
            v -= 10;
        }
        else if(v >= 5)
        {
            *(r+index) = 'V';
            index++;
            v -= 5;
        }
        else
        {
            *(r+index) = 'I';
            index++;
            v--;
        }
        /* prevent overflow */
        if(index == SIZE)
            break;
    }
    /* cap the string */
    *(r+index) = '\0';
}

The decimal2roman() function consists of a huge if-else structure. You can’t use a switch-case structure due to the comparisons required. A while loop monitors variable v, the decimal value passed to the function. The loop spins until v equals zero.

Pointer r in the function references a string that contains the Roman numeral characters.

At Line 36, if value v is greater than 1000, character 'M' is inserted into the string. The string pointer is incremented, then 1000 is subtracted from v.

Subsequent else-if tests peel out values 500, 100, 50, 10, 5, and finally 1. The if-else structure works as a filter, so that v only descends into the final statements once its value becomes small enough. All the time, string r is built up with Roman numerals in the proper order.

A test at Line 79 ensures that the string doesn’t overflow, or contain more characters than allocated in the buffer. Then, finally, at Line 83, the string is capped with a null character, '\0', and the function returns.

Here are some sample runs:

Type an integer value: 658
The value 658 is DCLVIII

Type an integer value: 1002
The value 1002 is MII

Type an integer value: 1234
The value 1234 is MCCXXXIIII

As you can see from the final output, the value IIII isn’t condensed to IV. That process requires more code, which I present in next week’s Lesson.

Leave a Reply