Home > Software engineering >  Program that converts from roman numerals to arabic numerals to roman sometimes gives wrong result
Program that converts from roman numerals to arabic numerals to roman sometimes gives wrong result

Time:05-21

I have this program that tries to convert from arabic to roman numbers to arabic numbers and it compiles without problems, but for certain values it gives the correct answer but for other cases it does not. For example:

11 is wrong (an X remains to the left of the Xs) 12 is wrong (an X remains to the left of the Xs)

20 is good

22 is wrong (2 X left over)

30 is good

32 is wrong (2 X left over)

40 is good

45 is bad (there is an XL left) 48 is wrong (an X remains before the second L)

50 is good

51 gives bad (left over an L) 58 is bad (left over an L)

60 is good

char *a2roman (int valor, char *c1, char *c2, char *c3);

int main (void)
{
    int ArabicNumber = 1;
    int result;
    char roman[15] = "";

    do
    {
        printf ("Enter an integer in the range 1 to 3000: \n\t");

        scanf ("%d", &ArabicNumber);
    }
    while ((ArabicNumber < 1) || (ArabicNumber > 3000));

    if ((ArabicNumber <= 3000) && (ArabicNumber >= 1000))
    {
        result = ArabicNumber / 1000;
        strcat (roman, a2roman(result, "M", " ", " "));
        ArabicNumber -= (result * 1000);
    }

    if ((ArabicNumber < 1000) && (ArabicNumber >= 100))
    {
        result = ArabicNumber / 100;
        strcat (roman, a2roman(result, "C", "D", "M"));
        ArabicNumber -= (result * 100);
    }

    if ((ArabicNumber < 100) && (ArabicNumber >= 10))
    {
        result = ArabicNumber / 10;
        strcat (roman, a2roman(result, "X", "L", "C"));
        ArabicNumber -= (result * 10);
    }

    if ((ArabicNumber < 10) && (ArabicNumber >= 1))
    {
        strcat (roman, a2roman(ArabicNumber, "I", "V", "X"));
    }

    printf ("The Roman numeral is: \n\t%s\n\n", roman);
    printf ("\t\t...Press any key to finish.");
    getch();

    return 0;
}

char *a2roman (int value, char *c1, char *c2, char *c3)
{
    int i;
    static char rRoman[15] = "";

    /* Si "valor" = 1, 2, 3 */
    if ((value >= 1) && (value <= 3))
    {
        for (i = 0; i < value; i  )
            strcat (rRoman, c1);
    }

    /* Si "valor" = 5, 6, 7, 8 */
    if ((value >= 5) && (value <= 8))
    {
        strcat (rRoman, c2);

        for (i = 0; i < (value - 5); i  )
            strcat (rRoman, c1);
    }

    /* Si "valor" = 4 */
    if (value == 4)
    {
        strcat (rRoman, c1);
        strcat (rRoman, c2);
    }

    /* Si "valor" = 9 */
    if (value == 9)
    {
        strcat (rRoman, c1);
        strcat (rRoman, c3);
    }

    return (rRoman);
}

CodePudding user response:

The static buffer inside a2roman builds up the complete result but each time it is called from main the partial result is also concatenated to the buffer that is printed out so you get duplicates if a2roman is called more than once.

One solution would be to use the return value from a2roman directly after the full result has been constructed by making roman a pointer and assigning the return value from a2roman to it each time a2roman is called like:

char* roman = NULL;
...
roman = a2roman(result, "M", " ", " ");
...
roman = a2roman(result, "C", "D", "M");
...
printf ("The Roman numeral is: \n\t%s\n\n", roman);

But if you ever wanted to convert more than one number you'd still have a problem because of the static buffer. You could clear it between numbers if you had a pointer to it, like *roman = 0; but that still feels messy to me.

A different solution is to pass in the buffer you want the number to be constructed in.

The following example shows how you could do that and also cleans up a little bit of the logic used to break the number into digits. What you had works but I figured I might as well show an alternate method and save a few lines.

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

void addDigit(char* out, int digit, const char* c1, const char* c2, const char* c3)
{
    if ((digit >= 1) && (digit <= 3))
    {
        for (int i = 0; i < digit; i  )
        {
            strcat(out, c1);
        }
    }

    if ((digit >= 5) && (digit <= 8))
    {
        strcat(out, c2);

        for (int i = 0; i < (digit - 5); i  )
        {
            strcat(out, c1);
        }
    }

    if (digit == 4)
    {
        strcat(out, c1);
        strcat(out, c2);
    }

    if (digit == 9)
    {
        strcat(out, c1);
        strcat(out, c3);
    }
}

void convertNumber(char* out, int num)
{
    if ((num <= 3000) && (num >= 1000))
    {
        addDigit(out, num / 1000, "M", " ", " ");
        num %= 1000;
    }

    if ((num < 1000) && (num >= 100))
    {
        addDigit(out, num / 100, "C", "D", "M");
        num %= 100;
    }

    if ((num < 100) && (num >= 10))
    {
        addDigit(out, num / 10, "X", "L", "C");
        num %= 10;
    }

    if ((num < 10) && (num >= 1))
    {
        addDigit(out, num, "I", "V", "X");
    }
}

int main(void)
{
    for (int i = 1; i < 100; i  = 3)
    {
        char buf[32] = { 0 };
        convertNumber(buf, i);
        printf("M = %s\n", i, buf);

    }
    for (int i = 101; i < 3000; i  = 101)
    {
        char buf[32] = { 0 };
        convertNumber(buf, i);
        printf("M = %s\n", i, buf);
    }
    return 0;
}

Online Example

Output:

   1 = I
   4 = IV
   7 = VII
  10 = X
  13 = XIII
  16 = XVI
  19 = XIX
  22 = XXII
  25 = XXV
  28 = XXVIII
  31 = XXXI
  34 = XXXIV
  37 = XXXVII
  40 = XL
  43 = XLIII
  46 = XLVI
  49 = XLIX
  52 = LII
  55 = LV
  58 = LVIII
  61 = LXI
  64 = LXIV
  67 = LXVII
  70 = LXX
  73 = LXXIII
  76 = LXXVI
  79 = LXXIX
  82 = LXXXII
  85 = LXXXV
  88 = LXXXVIII
  91 = XCI
  94 = XCIV
  97 = XCVII
 101 = CI
 202 = CCII
 303 = CCCIII
 404 = CDIV
 505 = DV
 606 = DCVI
 707 = DCCVII
 808 = DCCCVIII
 909 = CMIX
1010 = MX
1111 = MCXI
1212 = MCCXII
1313 = MCCCXIII
1414 = MCDXIV
1515 = MDXV
1616 = MDCXVI
1717 = MDCCXVII
1818 = MDCCCXVIII
1919 = MCMXIX
2020 = MMXX
2121 = MMCXXI
2222 = MMCCXXII
2323 = MMCCCXXIII
2424 = MMCDXXIV
2525 = MMDXXV
2626 = MMDCXXVI
2727 = MMDCCXXVII
2828 = MMDCCCXXVIII
2929 = MMCMXXIX
  • Related