Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert integer value to Roman numeral string?

Tags:

How can I convert an integer to its String representation in Roman numerals in C ?

like image 807
Vishwanath Dalvi Avatar asked Feb 13 '11 20:02

Vishwanath Dalvi


People also ask

How do you convert int to Roman in Python?

Divide the given number into digits at different places like one's, two's, hundred's, or thousand's. Starting from the thousand's place print the corresponding roman value. For example, if the digit at thousand's place is 3 then print the roman equivalent of 3000. Repeat the second step until we reach one's place.

How do you convert int to Roman numerals in C++?

We take the corresponding roman value from the map and append it to our answer. At first, we process 6 thus ans = VI and our integer becomes 240. Second, we process 40 thus ans = XLVI and the integer become 200. Third, we process 200 and ans = CCXLVI and our loop terminates.


2 Answers

The easiest way is probably to set up three arrays for the complex cases and use a simple function like:

// convertToRoman: //   In:  val: value to convert. //        res: buffer to hold result. //   Out: n/a //   Cav: caller responsible for buffer size.  void convertToRoman (unsigned int val, char *res) {     char *huns[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};     char *tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};     char *ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};     int   size[] = { 0,   1,    2,     3,    2,   1,    2,     3,      4,    2};      //  Add 'M' until we drop below 1000.      while (val >= 1000) {         *res++ = 'M';         val -= 1000;     }      // Add each of the correct elements, adjusting as we go.      strcpy (res, huns[val/100]); res += size[val/100]; val = val % 100;     strcpy (res, tens[val/10]);  res += size[val/10];  val = val % 10;     strcpy (res, ones[val]);     res += size[val];      // Finish string off.      *res = '\0'; } 

This will handle any unsigned integer although large numbers will have an awful lot of M characters at the front and the caller has to ensure their buffer is large enough.

Once the number has been reduced below 1000, it's a simple 3-table lookup, one each for the hundreds, tens and units. For example, take the case where val is 314.

val/100 will be 3 in that case so the huns array lookup will give CCC, then val = val % 100 gives you 14 for the tens lookup.

Then val/10 will be 1 in that case so the tens array lookup will give X, then val = val % 10 gives you 4 for the ones lookup.

Then val will be 4 in that case so the ones array lookup will give IV.

That gives you CCCXIV for 314.


A buffer-overflow-checking version is a simple step up from there:

// convertToRoman: //   In:  val: value to convert. //        res: buffer to hold result. //   Out: returns 0 if not enough space, else 1. //   Cav: n/a  int convertToRoman (unsigned int val, char *res, size_t sz) {     char *huns[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};     char *tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};     char *ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};     int   size[] = { 0,   1,    2,     3,    2,   1,    2,     3,      4,    2};      //  Add 'M' until we drop below 1000.      while (val >= 1000) {         if (sz-- < 1) return 0;         *res++ = 'M';         val -= 1000;     }      // Add each of the correct elements, adjusting as we go.      if (sz < size[val/100]) return 0;     sz -= size[val/100];     strcpy (res, huns[val/100]);     res += size[val/100];     val = val % 100;      if (sz < size[val/10]) return 0;     sz -= size[val/10];     strcpy (res, tens[val/10]);     res += size[val/10];     val = val % 10;      if (sz < size[val) return 0;     sz -= size[val];     strcpy (res, ones[val]);     res += size[val];      // Finish string off.      if (sz < 1) return 0;     *res = '\0';     return 1; } 

although, at that point, you could think of refactoring the processing of hundreds, tens and units into a separate function since they're so similar. I'll leave that as an extra exercise.

like image 61
paxdiablo Avatar answered Oct 22 '22 20:10

paxdiablo


don't use a sissy pre-calculated map for the difficult cases.

/* roman.c */ #include <stdio.h>  /* LH(1) roman numeral conversion */ int RN_LH1 (char *buf, const size_t maxlen, int n) {   int S[]  = {    0,   2,   4,   2,   4,   2,   4 };   int D[]  = { 1000, 500, 100,  50,  10,   5,   1 };   char C[] = {  'M', 'D', 'C', 'L', 'X', 'V', 'I' };   const size_t L = sizeof(D) / sizeof(int) - 1;   size_t k = 0; /* index into output buffer */   int i = 0; /* index into maps */   int r, r2;    while (n > 0) {     if (D[i] <= n) {       r = n / D[i];       n = n - (r * D[i]);       /* lookahead */       r2 = n / D[i+1];       if (i < L && r2 >= S[i+1]) {         /* will violate repeat boundary on next pass */         n = n - (r2 * D[i+1]);         if (k < maxlen) buf[k++] = C[i+1];         if (k < maxlen) buf[k++] = C[i-1];       }       else if (S[i] && r >= S[i]) {         /* violated repeat boundary on this pass */         if (k < maxlen) buf[k++] = C[i];         if (k < maxlen) buf[k++] = C[i-1];       }       else         while (r-- > 0 && k < maxlen)           buf[k++] = C[i];     }     i++;   }   if (k < maxlen) buf[k] = '\0';   return k; }  /* gcc -Wall -ansi roman.c */ int main (int argc, char **argv) {   char buf[1024] = {'\0'};   size_t len;   int k;   for (k = 1991; k < 2047; k++)   {     len = RN_LH1(buf, 1023, k);     printf("%3lu % 4d %s\n", len, k, buf);   }   return 0; } 

you don't actually need to declare S either. it should be easy to see why.

like image 21
j. andrew shusta Avatar answered Oct 22 '22 18:10

j. andrew shusta