Kevin
Kevin

Reputation: 1151

Integer to number roman with macros

I have the following code that converts a number to number roman

#include <stdlib.h>
#include <stdio.h>

void roman(char *s, unsigned int n)
{
    if (n == 0)
    {
        fputs("Roman numeral zero does not exist ", stderr);
        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];
    unsigned int i;
    for (i = 1; i <= 100; ++i)
    {
        roman(buffer, i);
        printf("%4u: %s\n", i, buffer);
    }
    return EXIT_SUCCESS;
}

The trouble is I'm thinking in a version without macros but I find no feasible way to do without extending the code

someone has any idea to do this?

Upvotes: 0

Views: 103

Answers (1)

Bill Lynch
Bill Lynch

Reputation: 81976

It appears that you are implementing a table based integer to roman numbers system. You just happen to be implementing the table in code rather than in data.

Here's what it would look like if we encoded the conversions in an array. We can also simplify the logic by turning every if statement in your code above, into a while statement.

#include <assert.h>
#include <string.h>
#include <stdio.h>

static struct {
    unsigned decimal;
    char *roman;
} conversion_table[] = {
    {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" },
};

void roman(char *s, unsigned int n) {
    s[0] = '\0';

    for (int i=0; i < sizeof(conversion_table) / sizeof(*conversion_table); ++i) {
        while (n >= conversion_table[i].decimal) {
            n -= conversion_table[i].decimal;
            strcat(s, conversion_table[i].roman);
            s += strlen(s);
        }
    }
}

int main() {
    char s[100];

    roman(s, 1024);
    printf("%d == %s\n", 1024, s);
}

Which outputs:

1024 == MXXIV

Upvotes: 5

Related Questions