How can I convert an integer to its String representation in Roman numerals in C ?
How to convert integer value to Roman numeral string?
37.1k views Asked by Vishwanath Dalvi At
3
There are 3 answers
0
On
don't use a pre-calculated map for the troublesome bits! this is a solved problem in compilers (grammar rules).
/* roman.c */
#include <stdio.h>
/* LL(1) roman numeral conversion */
int RN_LL1 (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_LL1(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 after tracing a few examples, but, the sequence will just repeat indefinitely over (i % 2) with a special case for zero.
0
On
static string ConvertToRoman(int num)
{
int d = 0;
string result = "";
while (num > 0)
{
int n = num % 10;
result = DigitToRoman(n, d) + result;
d++;
num = num / 10;
}
return result;
}
static string DigitToRoman(int n, int d)
{
string[,] map = new string[3, 3] { { "I", "V", "X" }, { "X", "L", "C" }, { "C", "D", "M" } };
string result="";
if (d <= 2)
{
switch (n)
{
case 0:
result = "";
break;
case 1:
result = map[d, 0];
break;
case 2:
result = map[d, 0] + map[d, 0];
break;
case 3:
result = map[d, 0] + map[d, 0] + map[d, 0];
break;
case 4:
result = map[d, 0] + map[d, 1];
break;
case 5:
result = map[d, 1];
break;
case 6:
result = map[d, 1] + map[d, 0];
break;
case 7:
result = map[d, 1] + map[d, 0] + map[d, 0];
break;
case 8:
result = map[d, 1] + map[d, 0] + map[d, 0] + map[d, 0];
break;
case 9:
result = map[d, 0] + map[d, 2];
break;
}
}
else if (d == 3 && n < 5)
{
while (--n >= 0)
{
result += "M";
}
}
else
{
return "Error! Can't convert numbers larger than 4999.";
}
return result;
}
The easiest way is probably to set up three arrays for the complex cases and use a simple function like:
This will handle any unsigned integer although large numbers will have an awful lot of
Mcharacters 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
valis314.val/100will be3in that case so thehunsarray lookup will giveCCC, thenval = val % 100gives you14for thetenslookup.Then
val/10will be1in that case so thetensarray lookup will giveX, thenval = val % 10gives you4for theoneslookup.Then
valwill be4in that case so theonesarray lookup will giveIV.That gives you
CCCXIVfor314.A buffer-overflow-checking version is a simple step up from there:
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.