How can I convert an integer to its String representation in Roman numerals in C ?
How to convert integer value to Roman numeral string?
37k 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
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
is314
.val/100
will be3
in that case so thehuns
array lookup will giveCCC
, thenval = val % 100
gives you14
for thetens
lookup.Then
val/10
will be1
in that case so thetens
array lookup will giveX
, thenval = val % 10
gives you4
for theones
lookup.Then
val
will be4
in that case so theones
array lookup will giveIV
.That gives you
CCCXIV
for314
.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.