Integer to Roman Numerals

From Software Engineers Wiki
Jump to: navigation, search

Convert an integer value to a string in Roman numerals. Support number from 1 to 3999.

Roman numerals use alphabet letters to represent numbers. In this system,

  • I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000
  • A letter placed after another of greater value adds.
  • A letter placed before another of greater value subtracts.

Answer 1

void int_to_roman_numeral(char *str, unsigned int num)
{
        /* The number supported by this function is 1..3999 */
        if (num < 1 || num > 3999)
                return;

        while (num >= 1000) {
                *str++ = 'M';
                num -= 1000;
        }

        if (num >= 900) {
                *str++ = 'C';
                *str++ = 'M';
                num -= 900;
        } else if (num >= 500) {
                *str++ = 'D';
                num -= 500;
                while (num >= 100) {
                        *str++ = 'C';
                        num -= 100;
                }
        } else if (num >= 400) {
                *str++ = 'C';
                *str++ = 'D';
                num -= 400;
        } else if (num >= 100) {
                while (num >= 100) {
                        *str++ = 'C';
                        num -= 100;
                }
        }

        if (num >= 90) {
                *str++ = 'X';
                *str++ = 'C';
                num -= 90;
        } else if (num >= 50) {
                *str++ = 'L';
                num -= 50;
                while (num >= 10) {
                        *str++ = 'X';
                        num -= 10;
                }
        } else if (num >= 40) {
                *str++ = 'X';
                *str++ = 'L';
                num -= 40;
        } else if (num >= 10) {
                while (num >= 10) {
                        *str++ = 'X';
                        num -= 10;
                }
        }

        if (num >= 9) {
                *str++ = 'I';
                *str++ = 'X';
                num -= 9;
        } else if (num >= 5) {
                *str++ = 'V';
                num -= 5;
                while (num >= 1) {
                        *str++ = 'I';
                        num -= 1;
                }
        } else if (num >= 4) {
                *str++ = 'I';
                *str++ = 'V';
                num -= 4;
        } else if (num >= 1) {
                while (num >= 1) {
                        *str++ = 'I';
                        num -= 1;
                }
        }
}

Answer 2

If you don't feel comfortable repeating same logic multiple times,

void int_to_roman_numeral(char *str, unsigned int num)
{
        struct {
                unsigned int unit;
                char ch_unit_1;
                char ch_unit_5;
                char ch_next_unit;
        } roman_table[] = {
                { 100, 'C', 'D', 'M' },
                { 10, 'X', 'L', 'C' },
                { 1, 'I', 'V', 'X' },
        };

        unsigned int i;

        if (num < 1 || num > 3999)
                return;

        while (num >= 1000) {
                *str++ = 'M';
                num -= 1000;
        }

        for (i = 0; i < sizeof(roman_table) / sizeof(roman_table[0]); ++i) {
                if (num < roman_table[i].unit)
                        continue;
                if (num >= roman_table[i].unit * 9) {
                        *str++ = roman_table[i].ch_unit_1;
                        *str++ = roman_table[i].ch_next_unit;
                        num -= roman_table[i].unit * 9;
                } else if (num >= roman_table[i].unit * 5) {
                        *str++ = roman_table[i].ch_unit_5;
                        num -= roman_table[i].unit * 5;
                        while (num >= roman_table[i].unit) {
                                *str++ = roman_table[i].ch_unit_1;
                                num -= roman_table[i].unit;
                        }
                } else if (num >= roman_table[i].unit * 4) {
                        *str++ = roman_table[i].ch_unit_1;
                        *str++ = roman_table[i].ch_unit_5;
                        num -= roman_table[i].unit * 4;
                } else {
                        while (num >= roman_table[i].unit) {
                                *str++ = roman_table[i].ch_unit_1;
                                num -= roman_table[i].unit;
                        }
                }
        }

        *str = '\0';
}

Test program

int main(void)
{
        unsigned int i;
        unsigned int val;
        char str[256];

        for (i = 0; i < 3999; ++i) {
                int_to_roman_numeral(str, i);
                val = roman_numeral_to_int(str, NULL);
                if (val != i) {
                        printf("Error: %s is %u but got %u\n",
                                str, i, val);
                }
        }

        return 0;
}
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox